summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--.mailmap1
-rw-r--r--Android.mk19
-rw-r--r--CMakeLists.txt43
-rw-r--r--README.txt177
-rw-r--r--cmake/Modules/WaffleDefineCompilerFlags.cmake107
-rw-r--r--cmake/Modules/WaffleDefineOS.cmake2
-rw-r--r--cmake/Modules/WaffleDefineVersion.cmake4
-rw-r--r--cmake/Modules/WaffleFindDependencies.cmake5
-rw-r--r--cmake/Modules/WafflePrintConfigurationSummary.cmake9
-rw-r--r--cmake/Modules/WaffleValidateOptions.cmake13
-rw-r--r--debian/changelog12
-rw-r--r--doc/release-notes/waffle-1.5.0.txt50
-rw-r--r--examples/CMakeLists.txt2
-rw-r--r--examples/gl_basic.c71
-rw-r--r--examples/simple-x11-egl.c12
-rw-r--r--include/c99_compat.h113
-rw-r--r--include/waffle/waffle.h1
-rw-r--r--include/waffle_test/waffle_test.h12
-rw-r--r--man/waffle_display.3.xml2
-rw-r--r--man/waffle_dl.3.xml2
-rw-r--r--man/waffle_enum.3.xml1
-rw-r--r--man/waffle_get_proc_address.3.xml17
-rw-r--r--man/waffle_init.3.xml8
-rw-r--r--man/waffle_is_extension_in_string.3.xml2
-rw-r--r--man/wflinfo.1.xml1
-rw-r--r--pkg/archlinux/mingw-w64-waffle/PKGBUILD86
-rw-r--r--pkg/archlinux/waffle-1.4.0/.gitignore7
-rw-r--r--pkg/archlinux/waffle-1.4.0/PKGBUILD56
-rw-r--r--pkg/archlinux/waffle-1.4.1/PKGBUILD6
-rw-r--r--pkg/archlinux/waffle-git/PKGBUILD12
-rw-r--r--src/utils/CMakeLists.txt6
-rw-r--r--src/utils/wflinfo.c75
-rw-r--r--src/waffle/CMakeLists.txt63
-rw-r--r--src/waffle/android/droid_surfaceflingerlink.cpp10
-rw-r--r--src/waffle/api/api_priv.h3
-rw-r--r--src/waffle/api/waffle_gl_misc.c5
-rw-r--r--src/waffle/api/waffle_init.c11
-rw-r--r--src/waffle/core/wcore_attrib_list.c2
-rw-r--r--src/waffle/core/wcore_display.c8
-rw-r--r--src/waffle/core/wcore_display.h2
-rw-r--r--src/waffle/core/wcore_error.c3
-rw-r--r--src/waffle/core/wcore_error_unittest.c50
-rw-r--r--src/waffle/core/wcore_platform.h1
-rw-r--r--src/waffle/core/wcore_tinfo.c36
-rw-r--r--src/waffle/core/wcore_util.c1
-rw-r--r--src/waffle/egl/wegl_config.c8
-rw-r--r--src/waffle/egl/wegl_context.c26
-rw-r--r--src/waffle/egl/wegl_display.c24
-rw-r--r--src/waffle/egl/wegl_platform.c113
-rw-r--r--src/waffle/egl/wegl_platform.h82
-rw-r--r--src/waffle/egl/wegl_util.c25
-rw-r--r--src/waffle/egl/wegl_util.h3
-rw-r--r--src/waffle/egl/wegl_window.c23
-rw-r--r--src/waffle/gbm/wgbm_display.c11
-rw-r--r--src/waffle/gbm/wgbm_platform.c65
-rw-r--r--src/waffle/gbm/wgbm_platform.h25
-rw-r--r--src/waffle/gbm/wgbm_window.c23
-rw-r--r--src/waffle/gbm/wgbm_window.h1
-rw-r--r--src/waffle/glx/glx_config.c7
-rw-r--r--src/waffle/glx/glx_context.c7
-rw-r--r--src/waffle/glx/glx_display.c5
-rw-r--r--src/waffle/glx/glx_platform.c57
-rw-r--r--src/waffle/glx/glx_platform.h25
-rw-r--r--src/waffle/glx/glx_window.c4
-rw-r--r--src/waffle/glx/glx_window.h2
-rw-r--r--src/waffle/glx/glx_wrappers.h50
-rw-r--r--src/waffle/waffle.def.in33
-rw-r--r--src/waffle/wayland/wayland_platform.c22
-rw-r--r--src/waffle/wayland/wayland_platform.h8
-rw-r--r--src/waffle/wgl/wgl_config.c302
-rw-r--r--src/waffle/wgl/wgl_config.h61
-rw-r--r--src/waffle/wgl/wgl_context.c212
-rw-r--r--src/waffle/wgl/wgl_context.h53
-rw-r--r--src/waffle/wgl/wgl_display.c275
-rw-r--r--src/waffle/wgl/wgl_display.h81
-rw-r--r--src/waffle/wgl/wgl_dl.c143
-rw-r--r--src/waffle/wgl/wgl_dl.h43
-rw-r--r--src/waffle/wgl/wgl_error.c48
-rw-r--r--src/waffle/wgl/wgl_error.h32
-rw-r--r--src/waffle/wgl/wgl_platform.c173
-rw-r--r--src/waffle/wgl/wgl_platform.h53
-rw-r--r--src/waffle/wgl/wgl_window.c212
-rw-r--r--src/waffle/wgl/wgl_window.h77
-rw-r--r--src/waffle/xegl/xegl_platform.c22
-rw-r--r--src/waffle/xegl/xegl_platform.h8
-rw-r--r--src/waffle/xegl/xegl_window.c12
-rw-r--r--src/waffle_test/CMakeLists.txt2
-rw-r--r--src/waffle_test/wt_main.c4
-rw-r--r--src/waffle_test/wt_runner.c4
-rw-r--r--tests/functional/CMakeLists.txt25
-rw-r--r--tests/functional/gl_basic_test.c1393
-rw-r--r--third_party/getopt/CMakeLists.txt10
-rw-r--r--third_party/getopt/LICENSE45
-rw-r--r--third_party/getopt/getopt.h82
-rw-r--r--third_party/getopt/getopt_long.c511
-rw-r--r--third_party/threads/CMakeLists.txt23
-rw-r--r--third_party/threads/LICENSE28
-rw-r--r--third_party/threads/threads.h180
-rw-r--r--third_party/threads/threads_posix.c325
-rw-r--r--third_party/threads/threads_win32.c527
101 files changed, 5471 insertions, 1278 deletions
diff --git a/.gitignore b/.gitignore
index 85a607f..6981cd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ CMakeFiles
/install_manifest.txt
/CMakeCache.txt
+/CPackConfig.cmake
+/CPackSourceConfig.cmake
# ----------------------------------------------
# Ninja
@@ -30,6 +32,9 @@ Makefile
*.a
*.so
+/bin/gl_basic
+/bin/gl_basic_test
+/bin/simple-x11-egl
/bin/wflinfo
/doc/html/man/waffle.7.html
/doc/html/man/waffle_attrib_list.3.html
diff --git a/.mailmap b/.mailmap
index c4134be..39c3c16 100644
--- a/.mailmap
+++ b/.mailmap
@@ -4,6 +4,7 @@ Arun Sl <arun.sl@tcs.com>
Ben Widawsky <ben@bwidawsk.net>
Brian Paul <brianp@vmware.com>
Chad Versace <chad.versace@linux.intel.com> <chad@chad-versace.us>
+Chad Versace <chad.versace@linux.intel.com> <chad@kiwitree.net>
Emil Velikov <emil.l.velikov@gmail.com>
Jeff Bland <jksb@linux.com> <jksb@member.fsf.org>
Jordan Justen <jordan.l.justen@intel.com> <jljusten@gmail.com>
diff --git a/Android.mk b/Android.mk
index 3d45758..d86b563 100644
--- a/Android.mk
+++ b/Android.mk
@@ -7,9 +7,9 @@ waffle_top := $(LOCAL_PATH)
# !!! The version must be updated in tandem with the CMakeLists !!!
#
waffle_major_version := 1
-waffle_minor_version := 4
-waffle_patch_version := 4
-waffle_api_version := 0x0104
+waffle_minor_version := 5
+waffle_patch_version := 0
+waffle_api_version := 0x0105
waffle_android_major_version := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
waffle_android_minor_version := $(word 2, $(subst ., , $(PLATFORM_VERSION)))
@@ -27,8 +27,6 @@ $(waffle_top)/include/waffle/waffle_version.h: \
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := libwaffle-$(waffle_major_version)
-LOCAL_CC := $(TARGET_CC) -std=c99
-
LOCAL_CFLAGS := \
-DANDROID_STUB \
-DWAFFLE_API_VERSION=$(waffle_api_version) \
@@ -38,7 +36,10 @@ LOCAL_CFLAGS := \
-DWAFFLE_ANDROID_MINOR_VERSION=$(waffle_android_minor_version) \
-Wno-pointer-arith
+LOCAL_CFLAGS += -std=c99
+
LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
$(LOCAL_PATH)/include/waffle \
$(LOCAL_PATH)/src/ \
$(LOCAL_PATH)/src/waffle/api/ \
@@ -47,6 +48,7 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/src/waffle/linux/ \
$(LOCAL_PATH)/src/waffle/droid/ \
$(LOCAL_PATH)/third_party/khronos/ \
+ $(LOCAL_PATH)/third_party/threads/
LOCAL_SRC_FILES := \
src/waffle/core/wcore_tinfo.c \
@@ -71,18 +73,19 @@ LOCAL_SRC_FILES := \
src/waffle/egl/wegl_config.c \
src/waffle/egl/wegl_context.c \
src/waffle/egl/wegl_display.c \
+ src/waffle/egl/wegl_platform.c \
src/waffle/egl/wegl_util.c \
src/waffle/egl/wegl_window.c \
src/waffle/android/droid_platform.c \
src/waffle/android/droid_display.c \
src/waffle/android/droid_window.c \
src/waffle/android/droid_surfaceflingerlink.cpp \
+ third_party/threads/threads_posix.c
LOCAL_SHARED_LIBRARIES := \
- libEGL \
libdl \
libutils \
- libgui \
+ libgui
LOCAL_GENERATED_SOURCES := \
$(LOCAL_PATH)/include/waffle/waffle_version.h
@@ -93,7 +96,7 @@ LOCAL_COPY_HEADERS := \
include/waffle/waffle_glx.h \
include/waffle/waffle_version.h \
include/waffle/waffle_wayland.h \
- include/waffle/waffle_x11_egl.h \
+ include/waffle/waffle_x11_egl.h
LOCAL_COPY_HEADERS_TO := waffle-$(waffle_major_version)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 470cd67..6fabb54 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,6 +29,13 @@ cmake_minimum_required(VERSION 2.8.11)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules")
+# Set the default location for all build artifacts to traditionally named
+# top-level directories. CMake's default location for build artifacts varies
+# per artifact and is hard-to-guess.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
+
include(WaffleDefineOS)
include(WaffleFindDependencies)
include(Options.cmake)
@@ -93,6 +100,20 @@ include_directories(
src
)
+add_subdirectory(third_party/threads)
+include_directories(
+ third_party/threads
+ )
+set(THREADS_LIBRARIES threads_bundled)
+
+if(MSVC)
+ add_subdirectory(third_party/getopt)
+ include_directories(
+ third_party/getopt
+ )
+ set(GETOPT_LIBRARIES getopt_bundled)
+endif()
+
add_subdirectory(doc)
add_subdirectory(src)
add_subdirectory(include)
@@ -165,3 +186,25 @@ install(
# ------------------------------------------------------------------------------
include(WafflePrintConfigurationSummary)
+
+set (CPACK_SET_DESTDIR ON)
+set (CPACK_PACKAGE_VERSION_MAJOR ${waffle_major_version})
+set (CPACK_PACKAGE_VERSION_MINOR ${waffle_minor_version})
+set (CPACK_PACKAGE_VERSION_PATCH ${waffle_patch_version})
+
+# cpack detects win64 vs win32 only when msvc is available
+# reported upstream, fix (likely post cmake 3.0) pending
+if (MINGW)
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set (CPACK_SYSTEM_NAME win64)
+ endif ()
+endif ()
+
+# See http://www.vtk.org/Wiki/CMake:CPackPackageGenerators
+if (WIN32)
+ set (CPACK_GENERATOR "ZIP")
+else ()
+ set (CPACK_GENERATOR "TBZ2")
+endif ()
+
+include(CPack)
diff --git a/README.txt b/README.txt
index 1695347..c9ffee2 100644
--- a/README.txt
+++ b/README.txt
@@ -50,10 +50,12 @@ Waffle, see the following:
Build Requirements
==================
+Waffle uses CMake for its build system.
+
Linux
-----
-
-Waffle uses CMake for it build system.
+On Linux it's recommended to install the cmake package using your
+distribution package manager.
Archlinux: pacman -S cmake
Fedora 17: yum install cmake
@@ -97,6 +99,53 @@ a comman-separated list of any combination of "x11", "wayland", and "drm".
- Debian: apt-get install libgbm-dev libudev-dev
+Windows - cross-building under Linux
+------------------------------------
+Make sure that CMake is installed on your system.
+
+ Archlinux: pacman -S cmake
+ Fedora 17: yum install cmake
+ Debian: apt-get install cmake
+
+The MinGW-W64 cross-build toolchain is recommended and its CMake wrapper.
+
+ Archlinux: pacman -S mingw-w64-gcc mingw-w64-cmake (latter is in AUR)
+ Fedora 17: yum install FINISHME
+ Debian: apt-get install FINISHME
+
+
+Windows - native builds
+-----------------------
+Download and install the latest version CMake from the official website:
+
+ http://cmake.org/
+
+Install Microsoft Visual Studio 2013* or later.
+Install 'Visual C++' feature.
+
+Download OpenGL Core API and Extension Header Files.
+
+ http://www.opengl.org/registry/#headers
+
+Copy the header files to MSVC.
+
+ C:\Program Files\Microsoft Visual Studio 12.0\VC\include\GL
+
+
+[*] Waffle heavily requires on features introduced by the C99 standard. As
+such only reasonable compiler (at the time of writing) from the Microsoft
+Visual Compiler series is MSVC 2013. Building with older versions is likely
+to be broken.
+
+Windows - CYGWIN
+----------------
+Waffle is not tested to build under CYGWIN and is likely to be broken.
+Patches addressing it are more than welcome.
+
+For build requirements, build and installation instructions, refer to the
+Linux notes in the relevant sections.
+
+
Build and Installation
======================
@@ -114,6 +163,9 @@ or
1. Configure pkg-config
-----------------------
+Compiling for Windows does require any additional dependencies, as such
+this step can be omitted.
+
If any of Waffle's dependencies are installed in custom locations, you must
set the PKG_CONFIG_PATH environment variable. For example, if you installed
a dependeny into /usr/local, then:
@@ -123,23 +175,26 @@ a dependeny into /usr/local, then:
2. Configure CMake
------------------
+
+2.1 Linux and Mac
+-----------------
On Linux and Mac, running CMake with no arguments as below will configure
Waffle for a release build (optimized compiler flags and basic debug symbols)
and will auto-enable support for features whose dependencies are installed:
cmake .
-To manually control the configuration process, or to later modify the an already-configured source tree,
-run one of the following:
+To manually control the configuration process, or to later modify the an
+already-configured source tree, run one of the following:
# An ncurses interface to CMake configuration.
- ccamke $BUILD_DIR
+ ccmake .
# A graphical Qt interface to CMake configuration.
- cmake-gui $BUILD_DIR
+ cmake-gui .
# Edit the raw configuration file.
- vim $BUILD_DIR/CMakeCache.txt
+ vim CMakeCache.txt
All configuration options can also be set on the command line during the
*initial* invocation of cmake. For example, to configure Waffle for a debug
@@ -147,17 +202,117 @@ build, require support for Wayland, and install into '/usr' instead of
'/usr/local', run the following:
cmake -DCMAKE_BUILD_TYPE=Debug \
- -DCMAKE_INSTALL_PREFIX=/usr/local \
+ -DCMAKE_INSTALL_PREFIX=/usr \
-Dwaffle_has_wayland=1 \
.
+2.2 Windows - cross-building under Linux
+----------------------------------------
+The following sh snippet can be used to ease the configuration process.
+
+ _architectures="i686-w64-mingw32 x86_64-w64-mingw32"
+ unset LDFLAGS
+ for _arch in ${_architectures}; do
+ _install_prefix=/usr/${_arch}
+ mkdir -p build-${_arch} && pushd build-${_arch}
+ ${_arch}-cmake .. \
+ -DCMAKE_INSTALL_PREFIX=${_install_prefix} \
+ -DCMAKE_INSTALL_LIBDIR=${_install_prefix}/lib \
+ \
+ -Dwaffle_build_tests=0 \
+ -Dwaffle_build_examples=1
+ make
+ popd
+ done
+
+Make sure to adjust _install_prefix to "" if the resulting library will
+not be used for further cross-building.
+
+
+2.3 Windows - native builds
+---------------------------
+
+For native Windows builds, one must provide a generator argument and
+optionally a toolset if the resulting library must be compatible with
+Windows XP. When the resulting library is to be 64bit "Win64" needs to be
+appended to the generator argument.
+
+ @echo Configuring Waffle as Windows Vista compatible 32bit library
+ cmake -G "Visual Studio 12" -H%CD% -B%CD%\build\msvc32 -DCMAKE_INSTALL_PREFIX=""
+
+ @echo Configuring Waffle as Windows Vista compatible 64bit library
+ cmake -G "Visual Studio 12 Win64" -H%CD% -B%CD%\build\msvc64 -DCMAKE_INSTALL_PREFIX=""
+
+ @echo Configuring Waffle as Windows XP compatible 32bit library
+ cmake -G "Visual Studio 12" -T "v120_xp" -H%CD% -B%CD%\build\msvc32 -DCMAKE_INSTALL_PREFIX=""
+
+For alternative control of the configuration process, or to later modify an
+already-configured source tree, run the graphical Qt interface via:
+
+ cmake-gui
+
3. Build and Install
--------------------
+The following commands build Waffle, run its tests, installs the project and
+creates a binary archive in a platform agnostic way.
+
+Note that not all steps may be required in your case and the configuration
+settings (cache) are located in the current directory as indicated by ".".
+
+ cmake --build .
+ cmake --build . --target check
+ cmake --build . --target check-func
+ cmake --build . --target install
+ cpack
+
+Calling `cmake ... check` only runs unittests that do not access the native
+OpenGL platform. To run additional functional tests, which do access the
+native OpenGL platform, call `cmake ... check-func`.
+
+3.1 Linux and Mac
+-----------------
+On Linux and Mac the default CMake generator is Unix Makefiles, as such we
+can use an alternative version of the above commands:
make
make check
+ make check-func
make install
+ make package
+
+
+3.2 Windows - cross-building under Linux
+----------------------------------------
+
+ _architectures="i686-w64-mingw32 x86_64-w64-mingw32"
+ unset LDFLAGS
+ for _arch in ${_architectures}; do
+ pushd build-${_arch}
+ make
+ make install
+ make package
+ popd
+ done
+
+Note: Running the tests (`make check` and/or `make check-func`) is not tested
+but may work if the appropriate environment is setup via wine.
+
+
+3.3 Windows - native builds
+---------------------------
+One can manage the build/install/package process via Visual Studio's GUI
+or via the command line.
+
+When using the GUI open .\build\msvc*\waffle-VERSION.sln, where * can be
+either 32 or 64 depending on your requirements.
+
+If building via the command line, navigate to the correct folder and invoke
+the desired command as outlined in `Section 3. Build and Install`
+
+For example the following will build 32bit Waffle and will package/archive
+it into a file called waffle1-VERSION-win32.zip.
-Calling `make check` only runs unittests that do not access the native OpenGL
-platform. To run additional functional tests, which do access the native
-OpenGL platform, call `make check-func`.
+ @echo Preparing to build 32 bit version of waffle
+ cd .\build\msvc32
+ cmake --build .
+ cpack
diff --git a/cmake/Modules/WaffleDefineCompilerFlags.cmake b/cmake/Modules/WaffleDefineCompilerFlags.cmake
index 4d149c8..710b7e0 100644
--- a/cmake/Modules/WaffleDefineCompilerFlags.cmake
+++ b/cmake/Modules/WaffleDefineCompilerFlags.cmake
@@ -33,49 +33,98 @@ function(waffle_add_c_flag flag var)
endif()
endfunction()
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-set(CMAKE_C_FLAGS_DEBUG "-g3 -O0 -DDEBUG")
+if (NOT MSVC)
+ #
+ # compiler flags
+ #
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+ set(CMAKE_C_FLAGS_DEBUG "-g3 -O0 -DDEBUG")
-# Use '-g1' to produce enough debug info for generating backtraces, but not
-# enough for single-stepping.
-set(CMAKE_C_FLAGS_RELEASE "-g1 -O2 -DNDEBUG")
+ # Use '-g1' to produce enough debug info for generating backtraces, but not
+ # enough for single-stepping.
+ set(CMAKE_C_FLAGS_RELEASE "-g1 -O2 -DNDEBUG")
-waffle_add_c_flag("-Werror=implicit-function-declaration" WERROR_IMPLICIT_FUNCTION_DECLARATION)
-waffle_add_c_flag("-Werror=incompatible-pointer-types" WERROR_INCOMPATIBLE_POINTER_TYPES)
-waffle_add_c_flag("-Werror=int-conversion" WERROR_INT_CONVERSION)
+ waffle_add_c_flag("-Werror=implicit-function-declaration" WERROR_IMPLICIT_FUNCTION_DECLARATION)
+ waffle_add_c_flag("-Werror=incompatible-pointer-types" WERROR_INCOMPATIBLE_POINTER_TYPES)
+ waffle_add_c_flag("-Werror=int-conversion" WERROR_INT_CONVERSION)
+ waffle_add_c_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
-if(waffle_on_linux)
- # On MacOS, the SSE2 headers trigger this error.
- waffle_add_c_flag("-Werror=missing-prototypes" WERROR_MISSING_PROTOTYPES)
-endif()
+ if(waffle_on_linux)
+ # On MacOS, the SSE2 headers trigger this error.
+ waffle_add_c_flag("-Werror=missing-prototypes" WERROR_MISSING_PROTOTYPES)
+ endif()
+
+ if(MINGW)
+ # Avoid depending on MinGW runtime DLLs
+ check_c_compiler_flag(-static-libgcc HAVE_STATIC_LIBGCC_FLAG)
+ if (HAVE_STATIC_LIBGCC_FLAG)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -static-libgcc")
+ endif ()
+ else()
+ # Avoid using TLS with MinGW builds.
+ waffle_check_thread_local_storage()
+ endif()
+else()
+ # XXX: and update the threads code
+ # http://msdn.microsoft.com/en-us/library/aa383745.aspx
+ if(CMAKE_GENERATOR_TOOLSET MATCHES "_xp$")
+ # Windows XP
+ add_definitions(-D_WIN32_WINNT=0x0501 -DWINVER=0x0501)
+ else()
+ # Windows 7
+ add_definitions(-D_WIN32_WINNT=0x0601 -DWINVER=0x0601)
+ endif()
-waffle_check_thread_local_storage()
+ # Adjust warnings
+ add_definitions(-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
-if(waffle_has_tls)
- add_definitions(-DWAFFLE_HAS_TLS)
-endif()
+ # Use static runtime
+ # http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
+ foreach(flag_var
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
+ )
+ if(${flag_var} MATCHES "/MD")
+ string (REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif()
+ endforeach(flag_var)
-if(waffle_has_tls_model_initial_exec)
- add_definitions(-DWAFFLE_HAS_TLS_MODEL_INITIAL_EXEC)
endif()
if(waffle_on_mac)
add_definitions(-DWAFFLE_HAS_CGL)
endif()
-if(waffle_has_glx)
- add_definitions(-DWAFFLE_HAS_GLX)
-endif()
+if(waffle_on_linux)
+ if(waffle_has_glx)
+ add_definitions(-DWAFFLE_HAS_GLX)
+ endif()
-if(waffle_has_wayland)
- add_definitions(-DWAFFLE_HAS_WAYLAND)
-endif()
+ if(waffle_has_wayland)
+ add_definitions(-DWAFFLE_HAS_WAYLAND)
+ endif()
+
+ if(waffle_has_x11_egl)
+ add_definitions(-DWAFFLE_HAS_X11_EGL)
+ endif()
+
+ if(waffle_has_gbm)
+ add_definitions(-DWAFFLE_HAS_GBM)
+ endif()
+
+ if(waffle_has_tls)
+ add_definitions(-DWAFFLE_HAS_TLS)
+ endif()
+
+ if(waffle_has_tls_model_initial_exec)
+ add_definitions(-DWAFFLE_HAS_TLS_MODEL_INITIAL_EXEC)
+ endif()
-if(waffle_has_x11_egl)
- add_definitions(-DWAFFLE_HAS_X11_EGL)
+ add_definitions(-D_XOPEN_SOURCE=600)
endif()
-if(waffle_has_gbm)
- add_definitions(-DWAFFLE_HAS_GBM)
+if(waffle_on_windows)
+ add_definitions(-DWAFFLE_HAS_WGL)
endif()
diff --git a/cmake/Modules/WaffleDefineOS.cmake b/cmake/Modules/WaffleDefineOS.cmake
index c3ec3bb..38013a1 100644
--- a/cmake/Modules/WaffleDefineOS.cmake
+++ b/cmake/Modules/WaffleDefineOS.cmake
@@ -27,6 +27,8 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
set(waffle_on_linux true)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
set(waffle_on_mac true)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+ set(waffle_on_windows true)
else()
message(FATAL_ERROR "Unrecognized CMAKE_SYSTEM_NAME=\"${CMAKE_SYSTEM_NAME}\"")
endif()
diff --git a/cmake/Modules/WaffleDefineVersion.cmake b/cmake/Modules/WaffleDefineVersion.cmake
index c665b93..4965c0a 100644
--- a/cmake/Modules/WaffleDefineVersion.cmake
+++ b/cmake/Modules/WaffleDefineVersion.cmake
@@ -39,8 +39,8 @@
# Bump this to x.y.90 immediately after each waffle-x.y.0 release.
#
set(waffle_major_version "1")
-set(waffle_minor_version "4")
-set(waffle_patch_version "4")
+set(waffle_minor_version "5")
+set(waffle_patch_version "0")
set(waffle_version "${waffle_major_version}.${waffle_minor_version}.${waffle_patch_version}")
diff --git a/cmake/Modules/WaffleFindDependencies.cmake b/cmake/Modules/WaffleFindDependencies.cmake
index 9245772..3fd7338 100644
--- a/cmake/Modules/WaffleFindDependencies.cmake
+++ b/cmake/Modules/WaffleFindDependencies.cmake
@@ -80,3 +80,8 @@ if(waffle_on_linux)
waffle_pkg_config(gbm gbm)
waffle_pkg_config(libudev libudev)
endif()
+
+
+if(waffle_on_windows)
+ find_path(GLEXT_INCLUDE_DIR NAMES GL/wglext.h DOC "Include for GL/wglext.h")
+endif()
diff --git a/cmake/Modules/WafflePrintConfigurationSummary.cmake b/cmake/Modules/WafflePrintConfigurationSummary.cmake
index 2b66fae..1f38db5 100644
--- a/cmake/Modules/WafflePrintConfigurationSummary.cmake
+++ b/cmake/Modules/WafflePrintConfigurationSummary.cmake
@@ -32,6 +32,9 @@ message("Configuration summary")
message("-----------------------------------------------")
message("")
message("Supported platforms: ")
+if(waffle_on_mac)
+ message(" cgl")
+endif()
if(waffle_has_glx)
message(" glx")
endif()
@@ -44,15 +47,16 @@ endif()
if(waffle_has_gbm)
message(" gbm")
endif()
+if(waffle_on_windows)
+ message(" wgl")
+endif()
message("")
message("Dependencies:")
if(waffle_has_egl)
message(" egl_INCLUDE_DIRS: ${egl_INCLUDE_DIRS}")
- message(" egl_LDFLAGS: ${egl_LDFLAGS}")
endif()
if(waffle_has_glx)
message(" gl_INCLUDE_DIRS: ${gl_INCLUDE_DIRS}")
- message(" gl_LDFLAGS: ${gl_LDFLAGS}")
endif()
if(waffle_has_wayland)
message(" wayland-client_INCLUDE_DIRS: ${wayland-client_INCLUDE_DIRS}")
@@ -66,7 +70,6 @@ if(waffle_has_x11)
endif()
if(waffle_has_gbm)
message(" gbm_INCLUDE_DIRS: ${gbm_INCLUDE_DIRS}")
- message(" gbm_LDFLAGS: ${gbm_LDFLAGS}")
endif()
message("")
message("Build type:")
diff --git a/cmake/Modules/WaffleValidateOptions.cmake b/cmake/Modules/WaffleValidateOptions.cmake
index d9fc299..ea60b0e 100644
--- a/cmake/Modules/WaffleValidateOptions.cmake
+++ b/cmake/Modules/WaffleValidateOptions.cmake
@@ -135,4 +135,17 @@ elseif(waffle_on_mac)
if(waffle_has_x11_egl)
message(FATAL_ERROR "Option is not supported on Darwin: waffle_has_x11_egl.")
endif()
+elseif(waffle_on_windows)
+ if(waffle_has_gbm)
+ message(FATAL_ERROR "Option is not supported on Windows: waffle_has_gbm.")
+ endif()
+ if(waffle_has_glx)
+ message(FATAL_ERROR "Option is not supported on Windows: waffle_has_glx.")
+ endif()
+ if(waffle_has_wayland)
+ message(FATAL_ERROR "Option is not supported on Windows: waffle_has_wayland.")
+ endif()
+ if(waffle_has_x11_egl)
+ message(FATAL_ERROR "Option is not supported on Windows: waffle_has_x11_egl.")
+ endif()
endif()
diff --git a/debian/changelog b/debian/changelog
index 04dc41e..361f2d9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+waffle (1.5.0-1) unstable; urgency=low
+
+ * New upstream release
+
+ -- Jordan Justen <jordan.l.justen@intel.com> Tue, 16 Dec 2014 11:06:19 -0800
+
+waffle (1.5.0~rc1-1) unstable; urgency=low
+
+ * New upstream release candidate
+
+ -- Jordan Justen <jordan.l.justen@intel.com> Thu, 04 Dec 2014 23:18:00 -0800
+
waffle (1.4.3-1) unstable; urgency=low
* New upstream release
diff --git a/doc/release-notes/waffle-1.5.0.txt b/doc/release-notes/waffle-1.5.0.txt
new file mode 100644
index 0000000..8ca5028
--- /dev/null
+++ b/doc/release-notes/waffle-1.5.0.txt
@@ -0,0 +1,50 @@
+Waffle 1.5.0 Release Notes
+==========================
+
+Backwards compatibility notes
+-----------------------------
+Waffle 1.5.0 is backwards-compatible with Waffle 1.4.0, in ABI and API.
+
+
+New Features
+------------
+* Windows: Experimental support for WGL [Emil Velikov]
+
+ Emil graciously added support for the Windows WGL API this summer,
+ represented by the new enum 'WAFFLE_PLATFORM_WGL'. The plan is to convert
+ Piglit's Windows build to use this rather than GLUT.
+
+* wflinfo now prints the OpenGL shading language version. [Dylan Baker]
+
+* Linux: Some library dependencies converted from static to dynamic [Emil Velikov]
+
+ libwaffle on Linux no longer statically links to, and instead dynamically
+ opens, the libraries below. This change allows a single build of Waffle to be
+ deployed onto systems with and without these libraries.
+
+ libEGL
+ libGL
+ libgbm
+
+* Android: Experimental support for Android Lollipop. (Waffle builds on
+ Lollipop but may have critical bugs). [Yongqin Liu]
+
+
+Bugfixes since 1.4.0
+--------------------
+* cmake: Fix building with CMake 2.8.11
+* glx: Fix requirements for creation of ES2 context
+* wflinfo used glGetStringi incorrectly on Mali drivers.
+* gbm: Workaround Mesa linkage issue
+* gbm: Remove Mesa warning evoked by waffle_window_swap_buffers().
+
+
+Contributors since Waffle 1.4.0
+-------------------------------
+ 80 Emil Velikov <emil.l.velikov@gmail.com>
+ 39 Chad Versace <chad.versace@linux.intel.com>
+ 9 Jordan Justen <jordan.l.justen@intel.com>
+ 2 Frank Henigman <fjhenigman@chromium.org>
+ 2 Yongqin Liu <yongqin.liu@linaro.org>
+ 1 Dylan Baker <dylanx.c.baker@intel.com>
+ 1 José Fonseca <jfonseca@vmware.com>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 8392ecb..281ef47 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -21,7 +21,7 @@ endif()
# ----------------------------------------------------------------------------
add_executable(gl_basic gl_basic.c)
-target_link_libraries(gl_basic ${waffle_libname})
+target_link_libraries(gl_basic ${waffle_libname} ${GETOPT_LIBRARIES})
if(waffle_on_mac)
set_target_properties(gl_basic
diff --git a/examples/gl_basic.c b/examples/gl_basic.c
index 8e1a28c..69418c8 100644
--- a/examples/gl_basic.c
+++ b/examples/gl_basic.c
@@ -43,7 +43,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if !defined(_WIN32)
#include <time.h>
+#else
+#include <windows.h>
+#endif
#ifdef __APPLE__
# import <Foundation/NSAutoreleasePool.h>
@@ -57,13 +61,14 @@ removeXcodeArgs(int *argc, char **argv);
static const char *usage_message =
"usage:\n"
- " gl_basic --platform=android|cgl|gbm|glx|wayland|x11_egl\n"
+ " gl_basic --platform=android|cgl|gbm|glx|wayland|wgl|x11_egl\n"
" --api=gl|gles1|gles2|gles3\n"
" [--version=MAJOR.MINOR]\n"
" [--profile=core|compat|none]\n"
" [--forward-compatible]\n"
" [--debug]\n"
" [--resize-window]\n"
+ " [--window-size=WIDTHxHEIGHT]\n"
"\n"
"examples:\n"
" gl_basic --platform=glx --api=gl\n"
@@ -92,6 +97,7 @@ enum {
OPT_DEBUG,
OPT_FORWARD_COMPATIBLE,
OPT_RESIZE_WINDOW,
+ OPT_WINDOW_SIZE,
};
static const struct option get_opts[] = {
@@ -102,10 +108,19 @@ static const struct option get_opts[] = {
{ .name = "debug", .has_arg = no_argument, .val = OPT_DEBUG },
{ .name = "forward-compatible", .has_arg = no_argument, .val = OPT_FORWARD_COMPATIBLE },
{ .name = "resize-window", .has_arg = no_argument, .val = OPT_RESIZE_WINDOW },
+ { .name = "window-size", .has_arg = required_argument, .val = OPT_WINDOW_SIZE },
{ 0 },
};
-static void __attribute__((noreturn))
+#if defined(__GNUC__)
+#define NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define NORETURN __declspec(noreturn)
+#else
+#define NORETURN
+#endif
+
+static void NORETURN
error_printf(const char *fmt, ...)
{
va_list ap;
@@ -120,7 +135,8 @@ error_printf(const char *fmt, ...)
exit(EXIT_FAILURE);
}
-static void __attribute__((noreturn))
+
+static void NORETURN
usage_error_printf(const char *fmt, ...)
{
fflush(stdout);
@@ -177,15 +193,23 @@ enum {
GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002,
};
-#define WINDOW_WIDTH 320
-#define WINDOW_HEIGHT 240
+static int window_width = 320;
+static int window_height = 240;
-static void (*glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-static void (*glClear)(GLbitfield mask);
-static void (*glGetIntegerv)(GLenum pname, GLint *params);
-static void (*glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLvoid* data);
-static void (*glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
+#ifndef _WIN32
+#define APIENTRY
+#else
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+#endif
+
+static void (APIENTRY *glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+static void (APIENTRY *glClear)(GLbitfield mask);
+static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
+static void (APIENTRY *glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* data);
+static void (APIENTRY *glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
/// @brief Command line options.
struct options {
@@ -220,6 +244,7 @@ static const struct enum_map platform_map[] = {
{WAFFLE_PLATFORM_GBM, "gbm" },
{WAFFLE_PLATFORM_GLX, "glx" },
{WAFFLE_PLATFORM_WAYLAND, "wayland" },
+ {WAFFLE_PLATFORM_WGL, "wgl" },
{WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
{0, 0 },
};
@@ -326,6 +351,15 @@ parse_args(int argc, char *argv[], struct options *opts)
case OPT_RESIZE_WINDOW:
opts->resize_window = true;
break;
+ case OPT_WINDOW_SIZE: {
+ int match_count;
+ match_count = sscanf(optarg, "%dx%d", &window_width, &window_height);
+ if (match_count != 2) {
+ usage_error_printf("'%s' is not a valid window geometry",
+ optarg);
+ }
+ break;
+ }
default:
abort();
loop_get_opt = false;
@@ -367,14 +401,16 @@ draw(struct waffle_window *window, bool resize)
{
bool ok;
unsigned char *colors;
- int width = WINDOW_WIDTH;
- int height = WINDOW_HEIGHT;
+ int width = window_width;
+ int height = window_height;
+#if !defined(_WIN32)
static const struct timespec sleep_time = {
// 0.5 sec
.tv_sec = 0,
.tv_nsec = 500000000,
};
+#endif
for (int i = 0; i < 3; ++i) {
switch (i) {
@@ -419,7 +455,11 @@ draw(struct waffle_window *window, bool resize)
if (!ok)
return false;
+#if !defined(_WIN32)
nanosleep(&sleep_time, NULL);
+#else
+ Sleep(500);
+#endif
}
return true;
@@ -496,6 +536,8 @@ main(int argc, char **argv)
struct waffle_context *ctx;
struct waffle_window *window;
+ GLint context_flags = 0;
+
#ifdef __APPLE__
cocoa_init();
#endif
@@ -586,7 +628,7 @@ main(int argc, char **argv)
if (!ctx)
error_waffle();
- window = waffle_window_create(config, WINDOW_WIDTH, WINDOW_HEIGHT);
+ window = waffle_window_create(config, window_width, window_height);
if (!window)
error_waffle();
@@ -594,7 +636,6 @@ main(int argc, char **argv)
if (!ok)
error_waffle();
- GLint context_flags = 0;
if (opts.context_forward_compatible || opts.context_debug) {
glGetIntegerv(GL_CONTEXT_FLAGS, &context_flags);
}
diff --git a/examples/simple-x11-egl.c b/examples/simple-x11-egl.c
index ed26eaa..9e218ac 100644
--- a/examples/simple-x11-egl.c
+++ b/examples/simple-x11-egl.c
@@ -49,8 +49,16 @@ enum {
GL_COLOR_BUFFER_BIT = 0x00004000,
};
-static void (*glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-static void (*glClear)(GLbitfield mask);
+#ifndef _WIN32
+#define APIENTRY
+#else
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+#endif
+
+static void (APIENTRY *glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+static void (APIENTRY *glClear)(GLbitfield mask);
// ---------------------------------------------
diff --git a/include/c99_compat.h b/include/c99_compat.h
new file mode 100644
index 0000000..297df31
--- /dev/null
+++ b/include/c99_compat.h
@@ -0,0 +1,113 @@
+// Copyright 2012 Intel Corporation
+//
+// 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.
+
+#pragma once
+
+/*
+ * C99 restrict keyword
+ */
+#ifndef restrict
+# if defined(__GNUC__)
+# define restrict __restrict__
+# elif defined(_MSC_VER)
+ /* leave empty to prevent compiler wows - decl vs. def diff */
+# define restrict
+# else
+# define restrict
+# endif
+#endif
+
+/*
+ * C99 inline keyword
+ */
+#ifndef inline
+# if defined(__GNUC__)
+# define inline __inline__
+# elif defined(_MSC_VER)
+# define inline __inline
+# elif defined(__ICL)
+# define inline __inline
+# else
+# define inline
+# endif
+#endif
+
+/*
+ * C99 string manipulation functions - snprintf, strcasecmp
+ *
+ * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+ */
+#if defined(_MSC_VER)
+#include <stdarg.h> // for va_start, va_end
+#include <stdio.h> // for _vscprintf, _vscprintf_s
+#include <string.h>
+
+#define strcasecmp _stricmp
+#define snprintf c99_snprintf
+#define vsnprintf c99_vsnprintf
+
+static inline int
+c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
+{
+ int count = -1;
+
+ if (size != 0)
+ count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+ if (count == -1)
+ count = _vscprintf(format, ap);
+
+ return count;
+}
+
+static inline int
+c99_snprintf(char* str, size_t size, const char* format, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start(ap, format);
+ count = c99_vsnprintf(str, size, format, ap);
+ va_end(ap);
+
+ return count;
+}
+
+#else
+#include <strings.h>
+
+#endif
+
+/*
+ * strerror_r - strictly speaking not C99 function, but it's been around of
+ * ages in one shape or another.
+ *
+ * Under *NIX there are three flavours - XSI-compliant (POSIX.1-2001)
+ * or not, vs GNU-specific one. The POSIX one is available only under *NIX
+ * and is guaranteed to be thread-safe (as used in waffle).
+ * Under Windows the function is not thread-safe and thus it's depreciated.
+ */
+#if defined(_WIN32)
+#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
+#endif
diff --git a/include/waffle/waffle.h b/include/waffle/waffle.h
index 91f3434..e04b23f 100644
--- a/include/waffle/waffle.h
+++ b/include/waffle/waffle.h
@@ -103,6 +103,7 @@ enum waffle_enum {
WAFFLE_PLATFORM_WAYLAND = 0x0014,
WAFFLE_PLATFORM_X11_EGL = 0x0015,
WAFFLE_PLATFORM_GBM = 0x0016,
+ WAFFLE_PLATFORM_WGL = 0x0017,
// ------------------------------------------------------------------
// For waffle_config_choose()
diff --git a/include/waffle_test/waffle_test.h b/include/waffle_test/waffle_test.h
index c7517e8..32cd2b6 100644
--- a/include/waffle_test/waffle_test.h
+++ b/include/waffle_test/waffle_test.h
@@ -47,10 +47,22 @@
testgroup_##group##_setup, \
testgroup_##group##_teardown)
+/// This must be called only from test suite s passed to wt_main().
+#define TEST_RUN2(group, displayname, testname) \
+ wt_runner_run_test( \
+ #group, #displayname, \
+ test_##group##_##testname, \
+ testgroup_##group##_setup, \
+ testgroup_##group##_teardown)
+
/// @param test_runners is a list of functions that call TEST_RUN(). The list
/// is a null-terminated.
/// @return number of failed tests.
+#ifdef _WIN32
+int wt_main(int *argc, char **argv, void (__stdcall *test_suites[])(void));
+#else
int wt_main(int *argc, char **argv, void (*test_suites[])(void));
+#endif // _WIN32
#define TEST_PASS() wt_test_pass()
#define TEST_SKIP() wt_test_skip()
diff --git a/man/waffle_display.3.xml b/man/waffle_display.3.xml
index 755c632..824a01a 100644
--- a/man/waffle_display.3.xml
+++ b/man/waffle_display.3.xml
@@ -93,7 +93,7 @@ struct waffle_display;
given to <citerefentry><refentrytitle><function>waffle_init</function></refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
<para>
- On Android and CGL, <parameter>name</parameter> is ignored.
+ On Android, CGL and WGL <parameter>name</parameter> is ignored.
</para>
<para>
On the X11 platforms, GLX and X11/EGL, the function connects to the X11 display with the given
diff --git a/man/waffle_dl.3.xml b/man/waffle_dl.3.xml
index b089b93..463081f 100644
--- a/man/waffle_dl.3.xml
+++ b/man/waffle_dl.3.xml
@@ -74,7 +74,7 @@
<filename>libGL.so.1</filename>,
<filename>libGLESv1_CM.so</filename>,
<filename>libGLESv2.so</filename>, and
- <filename>libGLESv2.so</filename>, repectively.
+ <filename>libGLESv2.so</filename>, respectively.
</para>
<variablelist>
diff --git a/man/waffle_enum.3.xml b/man/waffle_enum.3.xml
index c6ad548..a96bd20 100644
--- a/man/waffle_enum.3.xml
+++ b/man/waffle_enum.3.xml
@@ -100,6 +100,7 @@ enum waffle_enum {
WAFFLE_PLATFORM_WAYLAND = 0x0014,
WAFFLE_PLATFORM_X11_EGL = 0x0015,
WAFFLE_PLATFORM_GBM = 0x0016,
+ WAFFLE_PLATFORM_WGL = 0x0017,
// ------------------------------------------------------------------
// For waffle_config_choose()
diff --git a/man/waffle_get_proc_address.3.xml b/man/waffle_get_proc_address.3.xml
index 36b9ea2..333e127 100644
--- a/man/waffle_get_proc_address.3.xml
+++ b/man/waffle_get_proc_address.3.xml
@@ -66,10 +66,13 @@
On CGL, this function returns <constant>NULL</constant>
because there exists no <function>CGLGetProcAdress()</function>.
+
+ On WGL, this redirects to
+ <citerefentry><refentrytitle><function>wglGetProcAddress</function></refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
<para>
- Some aspects of this function's behavior is platform-specific and non-intuitive.
+ Some aspects of this function's behavior are platform-specific and non-intuitive.
For example,
@@ -89,6 +92,14 @@
then <function>waffle_get_proc_address()</function> may return a <constant>NULL</constant>.
</para>
</listitem>
+
+ <listitem>
+ <para>
+ Under Windows (WGL) a current context must be available before executing the function.
+
+ Otherwise <function>waffle_get_proc_address()</function> may return a <constant>NULL</constant>.
+ </para>
+ </listitem>
</itemizedlist>
</para>
@@ -99,7 +110,9 @@
the <ulink url="http://www.opengl.org/registry/doc/glx1.4.pdf">GLX 1.4 Specification</ulink>
- or the <ulink url="http://www.khronos.org/registry/egl/specs/eglspec.1.4.20110406.pdf">EGL 1.4 Specification</ulink>.
+ the <ulink url="http://www.khronos.org/registry/egl/specs/eglspec.1.4.20110406.pdf">EGL 1.4 Specification</ulink>
+
+ or the <ulink url="http://msdn.microsoft.com/en-gb/library/windows/desktop/dd374386(v=vs.85).aspx">MSDN article</ulink>.
</para>
</listitem>
</varlistentry>
diff --git a/man/waffle_init.3.xml b/man/waffle_init.3.xml
index a1b9cd3..a22723d 100644
--- a/man/waffle_init.3.xml
+++ b/man/waffle_init.3.xml
@@ -129,6 +129,14 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><constant>WAFFLE_PLATFORM_WGL</constant></term>
+ <listitem>
+ <para>
+ [Windows] Use WGL on Windows.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><constant>WAFFLE_PLATFORM_X11_EGL</constant></term>
<listitem>
<para>
diff --git a/man/waffle_is_extension_in_string.3.xml b/man/waffle_is_extension_in_string.3.xml
index 2734ea2..2808639 100644
--- a/man/waffle_is_extension_in_string.3.xml
+++ b/man/waffle_is_extension_in_string.3.xml
@@ -69,7 +69,7 @@
Note that this function is not restricted to the OpenGL extension string;
- it can also be used on the GLX and EGL extension strings.
+ it can also be used on the WGL, GLX and EGL extension strings.
</para>
<para>
diff --git a/man/wflinfo.1.xml b/man/wflinfo.1.xml
index 4060f38..c75dcf7 100644
--- a/man/wflinfo.1.xml
+++ b/man/wflinfo.1.xml
@@ -76,6 +76,7 @@
<member>gbm</member>
<member>glx</member>
<member>wayland</member>
+ <member>wgl</member>
<member>x11_egl</member>
</simplelist>
</para>
diff --git a/pkg/archlinux/mingw-w64-waffle/PKGBUILD b/pkg/archlinux/mingw-w64-waffle/PKGBUILD
new file mode 100644
index 0000000..c563948
--- /dev/null
+++ b/pkg/archlinux/mingw-w64-waffle/PKGBUILD
@@ -0,0 +1,86 @@
+# Maintainer: Chad Versace <chad.versace@linux.intel.com>
+
+pkgname='mingw-w64-waffle'
+pkgver='1.3.0'
+pkgrel=1
+pkgdesc='a library for choosing window system and OpenGL API at runtime (mingw-w64)'
+arch=('any')
+url='http://waffle-gl.github.io'
+license=('BSD')
+
+depends=(
+ 'mingw-w64-crt>=3.1.0-3'
+ )
+makedepends=(
+ 'mingw-w64-cmake'
+
+ # For building the docs.
+# XXX: Add as soon as we enable docs/manpages
+# 'libxslt'
+# 'docbook-xsl'
+
+ )
+
+options=('!strip' '!buildflags' 'staticlibs')
+_architectures="i686-w64-mingw32 x86_64-w64-mingw32"
+
+if [[ ! -v _srcroot ]]; then
+ msg "Environment variable _srcroot is unset"
+ msg "Fall back to using git worktree for _srcroot ..."
+ _srcroot="$(git rev-parse --show-toplevel)" || exit
+ msg "Using _srcroot=$_srcroot"
+fi
+
+build() {
+ unset LDFLAGS
+ cd "${_srcroot}"
+ msg "Building mingw-w64-waffle for cross-building"
+ for _arch in ${_architectures}; do
+ mkdir -p build-${_arch} && pushd build-${_arch}
+ ${_arch}-cmake .. \
+ -DCMAKE_INSTALL_PREFIX=/usr/${_arch} \
+ -DCMAKE_INSTALL_LIBDIR=/usr/${_arch}/lib \
+ -DCMAKE_BUILD_TYPE=Release \
+ \
+ -Dwaffle_build_tests=0 \
+ -Dwaffle_build_manpages=0 \
+ -Dwaffle_build_htmldocs=0 \
+ -Dwaffle_build_examples=1
+ make
+ popd
+ done
+
+ # There should be a better way to do this
+ msg "Building mingw-w64-waffle for native builds"
+ for _arch in ${_architectures}; do
+ mkdir -p "build-${_arch}-win" && pushd "build-${_arch}-win"
+ ${_arch}-cmake .. \
+ -DCMAKE_INSTALL_PREFIX="" \
+ -DCMAKE_INSTALL_LIBDIR="lib" \
+ -DCMAKE_BUILD_TYPE=Release \
+ \
+ -Dwaffle_build_tests=0 \
+ -Dwaffle_build_manpages=0 \
+ -Dwaffle_build_htmldocs=0 \
+ -Dwaffle_build_examples=1
+ make
+ popd
+ done
+}
+
+package() {
+ for _arch in ${_architectures}; do
+ cd "${_srcroot}/build-${_arch}"
+ make DESTDIR="${pkgdir}" install
+# ${_arch}-strip --strip-unneeded "$pkgdir"/usr/${_arch}/bin/*.dll
+# ${_arch}-strip -g "$pkgdir"/usr/${_arch}/lib/*.a
+ done
+
+ for _arch in ${_architectures}; do
+ cd "${_srcroot}/build-${_arch}-win"
+ # Create Windows zip archives
+ make package
+ done
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/pkg/archlinux/waffle-1.4.0/.gitignore b/pkg/archlinux/waffle-1.4.0/.gitignore
new file mode 100644
index 0000000..f69628a
--- /dev/null
+++ b/pkg/archlinux/waffle-1.4.0/.gitignore
@@ -0,0 +1,7 @@
+pkg/
+src/
+waffle/
+
+*.gz
+*.sig
+*.xz
diff --git a/pkg/archlinux/waffle-1.4.0/PKGBUILD b/pkg/archlinux/waffle-1.4.0/PKGBUILD
new file mode 100644
index 0000000..61cd7ab
--- /dev/null
+++ b/pkg/archlinux/waffle-1.4.0/PKGBUILD
@@ -0,0 +1,56 @@
+# maintainer: chad versace <chad.versace@linux.intel.com>
+
+pkgname='waffle'
+pkgver='1.4.0'
+pkgrel=1
+pkgdesc='a library for choosing window system and OpenGL API at runtime'
+arch=('i686' 'x86_64')
+url='http://www.waffle-gl.org'
+license=('BSD')
+
+depends=(
+ 'libgl' # for glx
+ 'libegl'
+ 'libgbm'
+ 'libx11'
+ 'libxcb'
+ 'wayland'
+ )
+makedepends=(
+ 'cmake'
+ 'xcb-proto'
+
+ # for building the docs.
+ 'libxslt'
+ 'docbook-xsl'
+ )
+source=("http://www.waffle-gl.org/files/release/${pkgname}-${pkgver}/${pkgname}-${pkgver}.tar.xz")
+sha256sums=('3238b3da5d066750084c7cdd7b3e185bd8dce3a974cb1f804ccf0a8c87600923')
+
+_unpackdir="${pkgname}-${pkgver}"
+
+build() {
+ cd "$srcdir/$_unpackdir"
+ cmake \
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DCMAKE_INSTALL_LIBDIR=/usr/lib \
+ -DCMAKE_BUILD_TYPE=Release \
+ -Dwaffle_has_glx=1 \
+ -Dwaffle_has_x11_egl=1 \
+ -Dwaffle_has_wayland=1 \
+ -Dwaffle_has_gbm=1 \
+ -Dwaffle_build_manpages=1 \
+ -Dwaffle_build_htmldocs=1 \
+ -Dwaffle_build_examples=0
+ make
+}
+
+package() {
+ cd "$srcdir/${_unpackdir}"
+ make DESTDIR="$pkgdir/" install
+ install -m755 -d "$pkgdir/usr/share/licenses/$pkgname"
+ install -m644 "$pkgdir/usr/share/doc/waffle1/LICENSE.txt" \
+ "$pkgdir/usr/share/licenses/$pkgname/LICENSE.txt"
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/pkg/archlinux/waffle-1.4.1/PKGBUILD b/pkg/archlinux/waffle-1.4.1/PKGBUILD
index e877ddc..5426e4b 100644
--- a/pkg/archlinux/waffle-1.4.1/PKGBUILD
+++ b/pkg/archlinux/waffle-1.4.1/PKGBUILD
@@ -2,7 +2,7 @@
pkgname='waffle'
pkgver='1.4.1'
-pkgrel=1
+pkgrel=2
pkgdesc='a library for choosing window system and OpenGL API at runtime'
arch=('i686' 'x86_64')
url='http://www.waffle-gl.org'
@@ -34,10 +34,6 @@ build() {
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=/usr/lib \
-DCMAKE_BUILD_TYPE=Release \
- -Dwaffle_has_gbm=1 \
- -Dwaffle_has_glx=1 \
- -Dwaffle_has_x11_egl=1 \
- -Dwaffle_has_wayland=1 \
-Dwaffle_build_manpages=1 \
-Dwaffle_build_htmldocs=1 \
-Dwaffle_build_examples=0
diff --git a/pkg/archlinux/waffle-git/PKGBUILD b/pkg/archlinux/waffle-git/PKGBUILD
index b5a6d96..932595c 100644
--- a/pkg/archlinux/waffle-git/PKGBUILD
+++ b/pkg/archlinux/waffle-git/PKGBUILD
@@ -12,8 +12,6 @@ provides=(waffle)
conflicts=(waffle)
depends=(
'libgl' # for glx
- 'libegl'
- 'libgbm'
'libx11'
'libxcb'
'wayland'
@@ -22,6 +20,9 @@ makedepends=(
'cmake'
'xcb-proto'
+ 'libegl'
+ 'libgbm'
+
# for building the docs.
'libxslt'
'docbook-xsl'
@@ -43,10 +44,6 @@ build() {
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=/usr/lib \
-DCMAKE_BUILD_TYPE=Release \
- -Dwaffle_has_glx=1 \
- -Dwaffle_has_x11_egl=1 \
- -Dwaffle_has_wayland=1 \
- -Dwaffle_has_gbm=1 \
-Dwaffle_build_manpages=1 \
-Dwaffle_build_htmldocs=1 \
-Dwaffle_build_examples=0
@@ -54,6 +51,9 @@ build() {
}
package() {
+ optdepends=('libegl: for x11_egl, gbm or wayland support')
+ optdepends=('libgbm: for gbm support')
+
cd "$srcdir/${_unpackdir}"
make DESTDIR="$pkgdir/" install
install -m755 -d "$pkgdir/usr/share/licenses/$pkgname"
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
index 848702c..9cb6cc7 100644
--- a/src/utils/CMakeLists.txt
+++ b/src/utils/CMakeLists.txt
@@ -3,11 +3,7 @@
# ----------------------------------------------------------------------------
add_executable(wflinfo wflinfo.c)
-target_link_libraries(wflinfo ${waffle_libname})
-set_target_properties(wflinfo
- PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
- )
+target_link_libraries(wflinfo ${waffle_libname} ${GETOPT_LIBRARIES})
if(waffle_on_mac)
set_target_properties(wflinfo
diff --git a/src/utils/wflinfo.c b/src/utils/wflinfo.c
index 0907b4b..5a9195c 100644
--- a/src/utils/wflinfo.c
+++ b/src/utils/wflinfo.c
@@ -62,7 +62,7 @@ static const char *usage_message =
"\n"
"Required Parameters:\n"
" -p, --platform\n"
- " One of: android, cgl, gbm, glx, wayland or x11_egl\n"
+ " One of: android, cgl, gbm, glx, wayland, wgl or x11_egl\n"
"\n"
" -a, --api\n"
" One of: gl, gles1, gles2 or gles3\n"
@@ -123,7 +123,15 @@ strneq(const char *a, const char *b, size_t n)
return strncmp(a, b, n) == 0;
}
-static void __attribute__((noreturn))
+#if defined(__GNUC__)
+#define NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define NORETURN __declspec(noreturn)
+#else
+#define NORETURN
+#endif
+
+static void NORETURN
error_printf(const char *module, const char *fmt, ...)
{
va_list ap;
@@ -137,14 +145,14 @@ error_printf(const char *module, const char *fmt, ...)
exit(EXIT_FAILURE);
}
-static void __attribute__((noreturn))
+static void NORETURN
write_usage_and_exit(FILE *f, int exit_code)
{
fprintf(f, "%s", usage_message);
exit(exit_code);
}
-static void __attribute__((noreturn))
+static void NORETURN
usage_error_printf(const char *fmt, ...)
{
fprintf(stderr, "Wflinfo usage error: ");
@@ -201,6 +209,7 @@ enum {
GL_VERSION = 0x1F02,
GL_EXTENSIONS = 0x1F03,
GL_NUM_EXTENSIONS = 0x821D,
+ GL_SHADING_LANGUAGE_VERSION = 0x8B8C,
};
#define WINDOW_WIDTH 320
@@ -212,10 +221,18 @@ enum {
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
-static GLenum (*glGetError)(void);
-static void (*glGetIntegerv)(GLenum pname, GLint *params);
-static const GLubyte * (*glGetString)(GLenum name);
-static const GLubyte * (*glGetStringi)(GLenum name, GLint i);
+#ifndef _WIN32
+#define APIENTRY
+#else
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+#endif
+
+static GLenum (APIENTRY *glGetError)(void);
+static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
+static const GLubyte * (APIENTRY *glGetString)(GLenum name);
+static const GLubyte * (APIENTRY *glGetStringi)(GLenum name, GLint i);
/// @brief Command line options.
struct options {
@@ -251,6 +268,7 @@ static const struct enum_map platform_map[] = {
{WAFFLE_PLATFORM_GBM, "gbm" },
{WAFFLE_PLATFORM_GLX, "glx" },
{WAFFLE_PLATFORM_WAYLAND, "wayland" },
+ {WAFFLE_PLATFORM_WGL, "wgl" },
{WAFFLE_PLATFORM_X11_EGL, "x11_egl" },
{0, 0 },
};
@@ -519,16 +537,19 @@ print_wflinfo(const struct options *opts)
}
const char *vendor = (const char *) glGetString(GL_VENDOR);
- if (glGetError() != GL_NO_ERROR || vendor == NULL)
+ if (glGetError() != GL_NO_ERROR || vendor == NULL) {
vendor = "WFLINFO_GL_ERROR";
+ }
const char *renderer = (const char *) glGetString(GL_RENDERER);
- if (glGetError() != GL_NO_ERROR || renderer == NULL)
+ if (glGetError() != GL_NO_ERROR || renderer == NULL) {
renderer = "WFLINFO_GL_ERROR";
+ }
const char *version_str = (const char *) glGetString(GL_VERSION);
- if (glGetError() != GL_NO_ERROR || version_str == NULL)
+ if (glGetError() != GL_NO_ERROR || version_str == NULL) {
version_str = "WFLINFO_GL_ERROR";
+ }
const char *platform = enum_map_to_str(platform_map, opts->platform);
assert(platform != NULL);
@@ -554,8 +575,25 @@ print_wflinfo(const struct options *opts)
if (!glGetStringi && use_getstringi)
error_get_gl_symbol("glGetStringi");
- if (opts->verbose)
+ if (opts->verbose) {
+ // There are two exceptional cases where wflinfo may not get a
+ // version (or a valid version): one is in gles1 and the other
+ // is GL < 2.0. In these cases do not return WFLINFO_GL_ERROR,
+ // return None. This is preferable to returning WFLINFO_GL_ERROR
+ // because it creates a consistant interface for parsers
+ const char *language_str = "None";
+ if ((opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 20) ||
+ opts->context_api == WAFFLE_CONTEXT_OPENGL_ES2 ||
+ opts->context_api == WAFFLE_CONTEXT_OPENGL_ES3) {
+ language_str = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
+ if (glGetError() != GL_NO_ERROR || language_str == NULL) {
+ language_str = "WFLINFO_GL_ERROR";
+ }
+ }
+
+ printf("OpenGL shading language version string: %s\n", language_str);
print_extensions(use_getstringi);
+ }
return true;
}
@@ -744,26 +782,27 @@ gl_get_version(void)
static bool
gl_has_extension_GetString(const char *name)
{
- const size_t buf_len = 4096;
- char exts[buf_len];
+#define BUF_LEN 4096
+ char exts[BUF_LEN];
const uint8_t *exts_orig = glGetString(GL_EXTENSIONS);
if (glGetError()) {
error_printf("Wflinfo", "glGetInteger(GL_EXTENSIONS) failed");
}
- memcpy(exts, exts_orig, buf_len);
- exts[buf_len - 1] = 0;
+ memcpy(exts, exts_orig, BUF_LEN);
+ exts[BUF_LEN - 1] = 0;
char *ext = strtok(exts, " ");
do {
- if (strneq(ext, name, buf_len)) {
+ if (strneq(ext, name, BUF_LEN)) {
return true;
}
ext = strtok(NULL, " ");
} while (ext);
return false;
+#undef BUF_LEN
}
/// @brief Check if current context has an extension using glGetStringi().
@@ -1079,6 +1118,8 @@ main(int argc, char **argv)
if (!ok)
error_waffle();
+ glGetStringi = waffle_get_proc_address("glGetStringi");
+
ok = print_wflinfo(&opts);
if (!ok)
error_waffle();
diff --git a/src/waffle/CMakeLists.txt b/src/waffle/CMakeLists.txt
index ab10498..d76e029 100644
--- a/src/waffle/CMakeLists.txt
+++ b/src/waffle/CMakeLists.txt
@@ -16,12 +16,14 @@ include_directories(
glx
linux
wayland
+ wgl
x11
xegl
${egl_INCLUDE_DIRS}
${gbm_INCLUDE_DIRS}
${gl_INCLUDE_DIRS}
+ ${GLEXT_INCLUDE_DIR}
${libudev_INCLUDE_DIRS}
${wayland-client_INCLUDE_DIRS}
${wayland-egl_INCLUDE_DIRS}
@@ -32,17 +34,11 @@ include_directories(
# Target: waffle (shared library)
# ----------------------------------------------------------------------------
+list(APPEND waffle_libdeps
+ ${THREADS_LIBRARIES}
+ )
+
if(waffle_on_linux)
- if(waffle_has_egl)
- list(APPEND waffle_libdeps
- ${egl_LDFLAGS}
- )
- endif()
- if(waffle_has_glx)
- list(APPEND waffle_libdeps
- ${gl_LDFLAGS}
- )
- endif()
if(waffle_has_wayland)
list(APPEND waffle_libdeps
${wayland-client_LDFLAGS}
@@ -56,7 +52,6 @@ if(waffle_on_linux)
endif()
if(waffle_has_gbm)
list(APPEND waffle_libdeps
- ${gbm_LDFLAGS}
${libudev_LDFLAGS}
)
endif()
@@ -103,6 +98,7 @@ if(waffle_has_egl)
egl/wegl_config.c
egl/wegl_context.c
egl/wegl_display.c
+ egl/wegl_platform.c
egl/wegl_util.c
egl/wegl_window.c
)
@@ -161,6 +157,22 @@ if(waffle_has_gbm)
)
endif()
+if(waffle_on_windows)
+ list(APPEND waffle_sources
+ wgl/wgl_config.c
+ wgl/wgl_context.c
+ wgl/wgl_display.c
+ wgl/wgl_dl.c
+ wgl/wgl_error.c
+ wgl/wgl_platform.c
+ wgl/wgl_window.c
+ )
+
+ list(APPEND waffle_libdeps
+ opengl32.lib
+ )
+endif()
+
# CMake will pass to the C compiler only C sources. CMake does not recognize the
# .m extension and ignores any such files in the source lists. To coerce CMake
# to pass .m files to the compiler, we must lie and claim that they are
@@ -169,9 +181,20 @@ set_source_files_properties(
${waffle_sources}
PROPERTIES
LANGUAGE C
- COMPILE_FLAGS "-fvisibility=hidden"
)
+if(waffle_on_windows)
+ configure_file(
+ waffle.def.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/${waffle_libname}.def
+ @ONLY
+ )
+
+ list(APPEND waffle_sources
+ ${waffle_libname}.def
+ )
+endif()
+
include_directories(
${GLX_INLCLUDE_DIRS}
${X11_INCLUDE_DIRS}
@@ -204,14 +227,22 @@ target_link_libraries(${waffle_libname} ${waffle_libdeps})
set_target_properties(${waffle_libname}
PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
SOVERSION ${waffle_soversion}
VERSION ${waffle_soversion}.${waffle_minor_version}.${waffle_patch_version}
)
+if(waffle_on_windows)
+ set_target_properties(${waffle_libname}
+ PROPERTIES
+ PREFIX ""
+ )
+endif()
+
install(
TARGETS ${waffle_libname}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT libraries
)
@@ -235,8 +266,7 @@ target_link_libraries(waffle_static ${waffle_libdeps})
set_target_properties(waffle_static
PROPERTIES
- OUTPUT_NAME "waffle-${waffle_major_version}"
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+ OUTPUT_NAME "waffle-static-${waffle_major_version}"
)
# ----------------------------------------------------------------------------
@@ -258,8 +288,7 @@ function(add_unittest unittest_name)
waffle_static
)
add_custom_target(${unittest_name}_run
- DEPENDS ${unittest_name}
- COMMAND "${CMAKE_BINARY_DIR}/tests/${unittest_name}"
+ COMMAND "${unittest_name}"
)
add_dependencies(check ${unittest_name}_run)
diff --git a/src/waffle/android/droid_surfaceflingerlink.cpp b/src/waffle/android/droid_surfaceflingerlink.cpp
index 765f70f..397c86c 100644
--- a/src/waffle/android/droid_surfaceflingerlink.cpp
+++ b/src/waffle/android/droid_surfaceflingerlink.cpp
@@ -23,8 +23,9 @@
// 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.
-#if WAFFLE_ANDROID_MAJOR_VERSION >= 4 && \
- WAFFLE_ANDROID_MINOR_VERSION >= 1
+#if WAFFLE_ANDROID_MAJOR_VERSION == 4 && \
+ WAFFLE_ANDROID_MINOR_VERSION >= 1 || \
+ WAFFLE_ANDROID_MAJOR_VERSION >= 5
# include <gui/Surface.h>
# include <gui/SurfaceComposerClient.h>
#elif WAFFLE_ANROID_MAJOR_VERSION >= 4 && \
@@ -107,8 +108,9 @@ droid_setup_surface(
// The signature of SurfaceComposerClient::createSurface() differs across
// Android versions.
-#if WAFFLE_ANDROID_MAJOR_VERSION >= 4 && \
- WAFFLE_ANDROID_MINOR_VERSION >= 2
+#if WAFFLE_ANDROID_MAJOR_VERSION == 4 && \
+ WAFFLE_ANDROID_MINOR_VERSION >= 2 || \
+ WAFFLE_ANDROID_MAJOR_VERSION >= 5
pANWContainer->surface_control =
pSFContainer->composer_client->createSurface(
String8("Waffle Surface"),
diff --git a/src/waffle/api/api_priv.h b/src/waffle/api/api_priv.h
index 1fec575..51cf53c 100644
--- a/src/waffle/api/api_priv.h
+++ b/src/waffle/api/api_priv.h
@@ -39,7 +39,8 @@
// TODO: Implement WAFFLE_API for Apple.
//
#if defined(_WIN32)
-# define WAFFLE_API __declspec(dllexport)
+// Use module-definition file to restrict the exported symbols under windows.
+# define WAFFLE_API
#elif defined(__GNUC__) && __GNUC__ >= 4
# define WAFFLE_API __attribute__ ((visibility("default")))
#else
diff --git a/src/waffle/api/waffle_gl_misc.c b/src/waffle/api/waffle_gl_misc.c
index c746f52..138974d 100644
--- a/src/waffle/api/waffle_gl_misc.c
+++ b/src/waffle/api/waffle_gl_misc.c
@@ -25,6 +25,7 @@
#include <stddef.h>
#include <string.h>
+#include "c99_compat.h"
#include "api_priv.h"
@@ -34,10 +35,6 @@
#include "wcore_platform.h"
#include "wcore_window.h"
-#if __STDC_VERSION__ < 199901L
-# define restrict
-#endif
-
WAFFLE_API bool
waffle_is_extension_in_string(
const char *restrict extension_string,
diff --git a/src/waffle/api/waffle_init.c b/src/waffle/api/waffle_init.c
index b45c3ba..ebc6cd5 100644
--- a/src/waffle/api/waffle_init.c
+++ b/src/waffle/api/waffle_init.c
@@ -34,6 +34,7 @@ struct wcore_platform* glx_platform_create(void);
struct wcore_platform* wayland_platform_create(void);
struct wcore_platform* xegl_platform_create(void);
struct wcore_platform* wgbm_platform_create(void);
+struct wcore_platform* wgl_platform_create(void);
static bool
waffle_init_parse_attrib_list(
@@ -97,6 +98,12 @@ waffle_init_parse_attrib_list(
CASE_UNDEFINED_PLATFORM(GBM)
#endif
+#ifdef WAFFLE_HAS_WGL
+ CASE_DEFINED_PLATFORM(WGL)
+#else
+ CASE_UNDEFINED_PLATFORM(WGL)
+#endif
+
default:
wcore_errorf(WAFFLE_ERROR_BAD_ATTRIBUTE,
"WAFFLE_PLATFORM has bad value 0x%x",
@@ -153,6 +160,10 @@ waffle_init_create_platform(int32_t waffle_platform)
case WAFFLE_PLATFORM_GBM:
return wgbm_platform_create();
#endif
+#ifdef WAFFLE_HAS_WGL
+ case WAFFLE_PLATFORM_WGL:
+ return wgl_platform_create();
+#endif
default:
assert(false);
return NULL;
diff --git a/src/waffle/core/wcore_attrib_list.c b/src/waffle/core/wcore_attrib_list.c
index ba380b8..48d4b33 100644
--- a/src/waffle/core/wcore_attrib_list.c
+++ b/src/waffle/core/wcore_attrib_list.c
@@ -40,7 +40,7 @@ wcore_attrib_list_length(const int32_t attrib_list[])
while (*i != 0)
i += 2;
- return (i - attrib_list) / 2;
+ return (int32_t) (i - attrib_list) / 2;
}
bool
diff --git a/src/waffle/core/wcore_display.c b/src/waffle/core/wcore_display.c
index 43e9e6a..a47e2c3 100644
--- a/src/waffle/core/wcore_display.c
+++ b/src/waffle/core/wcore_display.c
@@ -24,8 +24,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
-#include <pthread.h>
#include <stdio.h>
+#include "threads.h"
#include "wcore_display.h"
@@ -34,14 +34,14 @@ wcore_display_init(struct wcore_display *self,
struct wcore_platform *platform)
{
static size_t id_counter = 0;
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ static mtx_t mutex = _MTX_INITIALIZER_NP;
assert(self);
assert(platform);
- pthread_mutex_lock(&mutex);
+ mtx_lock(&mutex);
self->api.display_id = ++id_counter;
- pthread_mutex_unlock(&mutex);
+ mtx_unlock(&mutex);
self->platform = platform;
diff --git a/src/waffle/core/wcore_display.h b/src/waffle/core/wcore_display.h
index 0b95729..9a0357d 100644
--- a/src/waffle/core/wcore_display.h
+++ b/src/waffle/core/wcore_display.h
@@ -25,6 +25,8 @@
#pragma once
+#include "c99_compat.h"
+
#include "api_object.h"
#include "wcore_util.h"
diff --git a/src/waffle/core/wcore_error.c b/src/waffle/core/wcore_error.c
index e03642d..fdf70f8 100644
--- a/src/waffle/core/wcore_error.c
+++ b/src/waffle/core/wcore_error.c
@@ -23,14 +23,13 @@
// 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.
-#define _XOPEN_SOURCE 600 // for strerror_r
-
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "c99_compat.h"
#include "wcore_error.h"
#include "wcore_tinfo.h"
diff --git a/src/waffle/core/wcore_error_unittest.c b/src/waffle/core/wcore_error_unittest.c
index e5d6cba..0ac667b 100644
--- a/src/waffle/core/wcore_error_unittest.c
+++ b/src/waffle/core/wcore_error_unittest.c
@@ -23,17 +23,13 @@
// 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.
-#ifdef __linux__
-# define _XOPEN_SOURCE 600
-#endif
-
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#include <pthread.h>
+#include "c99_compat.h"
+#include "threads.h"
#include <cmocka.h>
@@ -131,7 +127,7 @@ enum {
NUM_THREADS = 3,
};
-/// Given to pthread_create() in test wcore_error.thread_local.
+/// Given to thrd_create() in test wcore_error.thread_local.
///
/// A sub-thread, after calling wcore_error(), locks the mutex, increments
/// `num_threads_waiting`, and waits on `cond`. When all sub-threads are
@@ -142,10 +138,10 @@ struct thread_arg {
int thread_id;
/// Protects `num_threads_waiting` and `cond`.
- pthread_mutex_t *mutex;
+ mtx_t *mutex;
/// Satisfied when `num_threads_waiting == TOTAL_THREADS`.
- pthread_cond_t *cond;
+ cnd_t *cond;
/// Number of threads waiting on `cond`.
volatile int *num_threads_waiting;
@@ -172,10 +168,10 @@ thread_start(struct thread_arg *a)
// Wait for all threads to set their error codes, thus giving
// the threads opportunity to clobber each other's codes.
- pthread_mutex_lock(a->mutex); {
+ mtx_lock(a->mutex); {
*a->num_threads_waiting += 1;
- pthread_cond_wait(a->cond, a->mutex);
- pthread_mutex_unlock(a->mutex);
+ cnd_wait(a->cond, a->mutex);
+ mtx_unlock(a->mutex);
}
// Verify that the threads did not clobber each other's
@@ -188,26 +184,26 @@ thread_start(struct thread_arg *a)
// Test that threads do not clobber each other's error codes.
static void
test_wcore_error_thread_local(void **state) {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
+ mtx_t mutex;
+ cnd_t cond;
volatile int num_threads_waiting = 0;
- pthread_t threads[NUM_THREADS];
+ thrd_t threads[NUM_THREADS];
struct thread_arg thread_args[NUM_THREADS];
- bool exit_codes[NUM_THREADS];
+ int exit_codes[NUM_THREADS];
- pthread_mutex_init(&mutex, NULL);
- pthread_cond_init(&cond, NULL);
+ mtx_init(&mutex, mtx_plain);
+ cnd_init(&cond);
- for (intptr_t i = 0; i < NUM_THREADS; ++i) {
+ for (int i = 0; i < NUM_THREADS; ++i) {
struct thread_arg *a = &thread_args[i];
a->thread_id = i;
a->mutex = &mutex;
a->cond = &cond;
a->num_threads_waiting = &num_threads_waiting;
- pthread_create(&threads[i], NULL,
- (void* (*)(void*)) thread_start,
+ thrd_create(&threads[i],
+ (thrd_start_t) thread_start,
(void*) a);
}
@@ -215,18 +211,18 @@ test_wcore_error_thread_local(void **state) {
// the threads opportunity to clobber each other's codes.
while (num_threads_waiting < NUM_THREADS)
;;
- pthread_mutex_lock(&mutex); {
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mutex);
+ mtx_lock(&mutex); {
+ cnd_broadcast(&cond);
+ mtx_unlock(&mutex);
}
for (int i = 0; i < NUM_THREADS; ++i) {
- pthread_join(threads[i], (void**) &exit_codes[i]);
+ thrd_join(threads[i], &exit_codes[i]);
assert_true(exit_codes[i]);
}
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mutex);
+ cnd_destroy(&cond);
+ mtx_destroy(&mutex);
}
int
diff --git a/src/waffle/core/wcore_platform.h b/src/waffle/core/wcore_platform.h
index 65de879..77943e4 100644
--- a/src/waffle/core/wcore_platform.h
+++ b/src/waffle/core/wcore_platform.h
@@ -28,6 +28,7 @@
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
+#include "c99_compat.h"
struct wcore_config;
struct wcore_config_attrs;
diff --git a/src/waffle/core/wcore_tinfo.c b/src/waffle/core/wcore_tinfo.c
index df31085..9a190f9 100644
--- a/src/waffle/core/wcore_tinfo.c
+++ b/src/waffle/core/wcore_tinfo.c
@@ -28,13 +28,13 @@
#include <stdio.h>
#include <stdlib.h>
-#include <pthread.h>
+#include "threads.h"
#include "wcore_error.h"
#include "wcore_tinfo.h"
-static pthread_once_t wcore_tinfo_once = PTHREAD_ONCE_INIT;
-static pthread_key_t wcore_tinfo_key;
+static once_flag wcore_tinfo_once = ONCE_FLAG_INIT;
+static tss_t wcore_tinfo_key;
#ifdef WAFFLE_HAS_TLS
/// @brief Thread-local storage for all of Waffle.
@@ -54,7 +54,15 @@ static __thread struct wcore_tinfo wcore_tinfo
;
#endif // WAFFLE_HAS_TLS
-static void __attribute__((noreturn))
+#if defined(__GNUC__)
+#define NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define NORETURN __declspec(noreturn)
+#else
+#define NORETURN
+#endif
+
+static void NORETURN
wcore_tinfo_abort_init(void)
{
printf("waffle: fatal-error: failed to initialize thread local info\n");
@@ -80,7 +88,7 @@ wcore_tinfo_key_create(void)
{
int err;
- err = pthread_key_create(&wcore_tinfo_key, wcore_tinfo_key_dtor);
+ err = tss_create(&wcore_tinfo_key, wcore_tinfo_key_dtor);
if (err)
wcore_tinfo_abort_init();
}
@@ -105,12 +113,13 @@ wcore_tinfo_init(struct wcore_tinfo *tinfo)
// each instance of tinfo must be registered individually. The key's data
// is never retrieved because use the key only to register tinfo for
// destruction.
- err = pthread_once(&wcore_tinfo_once, wcore_tinfo_key_create);
- if (err)
- wcore_tinfo_abort_init();
+
+ // With C11 threads call_once "can never fail"...
+ // http://open-std.org/twiki/pub/WG14/DefectReports/n1654.htm
+ call_once(&wcore_tinfo_once, wcore_tinfo_key_create);
#endif
- err = pthread_setspecific(wcore_tinfo_key, tinfo);
+ err = tss_set(wcore_tinfo_key, tinfo);
if (err)
wcore_tinfo_abort_init();
}
@@ -122,14 +131,13 @@ wcore_tinfo_get(void)
wcore_tinfo_init(&wcore_tinfo);
return &wcore_tinfo;
#else
- int err;
struct wcore_tinfo *tinfo;
- err = pthread_once(&wcore_tinfo_once, wcore_tinfo_key_create);
- if (err)
- wcore_tinfo_abort_init();
+ // With C11 threads call_once "can never fail"...
+ // http://open-std.org/twiki/pub/WG14/DefectReports/n1654.htm
+ call_once(&wcore_tinfo_once, wcore_tinfo_key_create);
- tinfo = pthread_getspecific(wcore_tinfo_key);
+ tinfo = tss_get(wcore_tinfo_key);
if (tinfo)
return tinfo;
diff --git a/src/waffle/core/wcore_util.c b/src/waffle/core/wcore_util.c
index 2276dde..deee1bf 100644
--- a/src/waffle/core/wcore_util.c
+++ b/src/waffle/core/wcore_util.c
@@ -61,6 +61,7 @@ wcore_enum_to_string(int32_t e)
CASE(WAFFLE_PLATFORM_WAYLAND);
CASE(WAFFLE_PLATFORM_X11_EGL);
CASE(WAFFLE_PLATFORM_GBM);
+ CASE(WAFFLE_PLATFORM_WGL);
CASE(WAFFLE_CONTEXT_API);
CASE(WAFFLE_CONTEXT_OPENGL);
CASE(WAFFLE_CONTEXT_OPENGL_ES1);
diff --git a/src/waffle/egl/wegl_config.c b/src/waffle/egl/wegl_config.c
index 5dbe1b6..db3d3c9 100644
--- a/src/waffle/egl/wegl_config.c
+++ b/src/waffle/egl/wegl_config.c
@@ -33,6 +33,7 @@
#include "wegl_config.h"
#include "wegl_display.h"
#include "wegl_imports.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
/// @brief Check the WAFFLE_CONTEXT_* attributes.
@@ -129,6 +130,7 @@ static EGLConfig
choose_real_config(struct wegl_display *dpy,
const struct wcore_config_attrs *attrs)
{
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
EGLConfig config = NULL;
bool ok = true;
@@ -189,10 +191,10 @@ choose_real_config(struct wegl_display *dpy,
}
EGLint num_configs = 0;
- ok &= eglChooseConfig(dpy->egl,
- attrib_list, &config, 1, &num_configs);
+ ok &= plat->eglChooseConfig(dpy->egl,
+ attrib_list, &config, 1, &num_configs);
if (!ok) {
- wegl_emit_error("eglChooseConfig");
+ wegl_emit_error(plat, "eglChooseConfig");
return NULL;
}
else if (num_configs == 0) {
diff --git a/src/waffle/egl/wegl_context.c b/src/waffle/egl/wegl_context.c
index abd6129..ba7d426 100644
--- a/src/waffle/egl/wegl_context.c
+++ b/src/waffle/egl/wegl_context.c
@@ -31,21 +31,22 @@
#include "wegl_config.h"
#include "wegl_context.h"
#include "wegl_imports.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
static bool
-bind_api(int32_t waffle_context_api)
+bind_api(struct wegl_platform *plat, int32_t waffle_context_api)
{
bool ok = true;
switch (waffle_context_api) {
case WAFFLE_CONTEXT_OPENGL:
- ok &= eglBindAPI(EGL_OPENGL_API);
+ ok &= plat->eglBindAPI(EGL_OPENGL_API);
break;
case WAFFLE_CONTEXT_OPENGL_ES1:
case WAFFLE_CONTEXT_OPENGL_ES2:
case WAFFLE_CONTEXT_OPENGL_ES3:
- ok &= eglBindAPI(EGL_OPENGL_ES_API);
+ ok &= plat->eglBindAPI(EGL_OPENGL_ES_API);
break;
default:
wcore_error_internal("waffle_context_api has bad value #x%x",
@@ -54,7 +55,7 @@ bind_api(int32_t waffle_context_api)
}
if (!ok)
- wegl_emit_error("eglBindAPI");
+ wegl_emit_error(plat, "eglBindAPI");
return ok;
}
@@ -65,6 +66,7 @@ create_real_context(struct wegl_config *config,
{
struct wegl_display *dpy = wegl_display(config->wcore.display);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
struct wcore_config_attrs *attrs = &config->wcore.attrs;
bool ok = true;
int32_t waffle_context_api = attrs->context_api;
@@ -142,14 +144,14 @@ create_real_context(struct wegl_config *config,
attrib_list[i++] = EGL_NONE;
- ok = bind_api(waffle_context_api);
+ ok = bind_api(plat, waffle_context_api);
if (!ok)
return false;
- EGLContext ctx = eglCreateContext(dpy->egl, config->egl,
- share_ctx, attrib_list);
+ EGLContext ctx = plat->eglCreateContext(dpy->egl, config->egl,
+ share_ctx, attrib_list);
if (!ctx)
- wegl_emit_error("eglCreateContext");
+ wegl_emit_error(plat, "eglCreateContext");
return ctx;
}
@@ -189,6 +191,8 @@ fail:
bool
wegl_context_destroy(struct wcore_context *wc_ctx)
{
+ struct wegl_display *dpy = wegl_display(wc_ctx->display);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
struct wegl_context *ctx;
bool result = true;
@@ -198,10 +202,10 @@ wegl_context_destroy(struct wcore_context *wc_ctx)
ctx = wegl_context(wc_ctx);
if (ctx->egl) {
- bool ok = eglDestroyContext(wegl_display(wc_ctx->display)->egl,
- ctx->egl);
+ bool ok = plat->eglDestroyContext(wegl_display(wc_ctx->display)->egl,
+ ctx->egl);
if (!ok) {
- wegl_emit_error("eglDestroyContext");
+ wegl_emit_error(plat, "eglDestroyContext");
result = false;
}
}
diff --git a/src/waffle/egl/wegl_display.c b/src/waffle/egl/wegl_display.c
index 0716a32..88fce7a 100644
--- a/src/waffle/egl/wegl_display.c
+++ b/src/waffle/egl/wegl_display.c
@@ -31,15 +31,17 @@
#include "wegl_display.h"
#include "wegl_imports.h"
#include "wegl_util.h"
+#include "wegl_platform.h"
static bool
get_extensions(struct wegl_display *dpy)
{
- const char *extensions = eglQueryString(dpy->egl, EGL_EXTENSIONS);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
+ const char *extensions = plat->eglQueryString(dpy->egl, EGL_EXTENSIONS);
if (!extensions) {
- wegl_emit_error("eglQueryString(EGL_EXTENSIONS");
- return false;
+ wegl_emit_error(plat, "eglQueryString(EGL_EXTENSIONS");
+ return false;
}
// waffle_is_extension_in_string() resets the error state. That's ok,
@@ -59,6 +61,7 @@ wegl_display_init(struct wegl_display *dpy,
struct wcore_platform *wc_plat,
intptr_t native_display)
{
+ struct wegl_platform *plat = wegl_platform(wc_plat);
bool ok;
EGLint major, minor;
@@ -66,21 +69,21 @@ wegl_display_init(struct wegl_display *dpy,
if (!ok)
goto fail;
- dpy->egl = eglGetDisplay((EGLNativeDisplayType) native_display);
+ dpy->egl = plat->eglGetDisplay((EGLNativeDisplayType) native_display);
if (!dpy->egl) {
- wegl_emit_error("eglGetDisplay");
+ wegl_emit_error(plat, "eglGetDisplay");
goto fail;
}
- ok = eglInitialize(dpy->egl, &major, &minor);
+ ok = plat->eglInitialize(dpy->egl, &major, &minor);
if (!ok) {
- wegl_emit_error("eglInitialize");
+ wegl_emit_error(plat, "eglInitialize");
goto fail;
}
ok = get_extensions(dpy);
if (!ok)
- goto fail;
+ goto fail;
return true;
@@ -92,12 +95,13 @@ fail:
bool
wegl_display_teardown(struct wegl_display *dpy)
{
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
bool ok = true;
if (dpy->egl) {
- ok = eglTerminate(dpy->egl);
+ ok = plat->eglTerminate(dpy->egl);
if (!ok)
- wegl_emit_error("eglTerminate");
+ wegl_emit_error(plat, "eglTerminate");
}
return ok;
diff --git a/src/waffle/egl/wegl_platform.c b/src/waffle/egl/wegl_platform.c
new file mode 100644
index 0000000..196b14a
--- /dev/null
+++ b/src/waffle/egl/wegl_platform.c
@@ -0,0 +1,113 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <dlfcn.h>
+
+#include "wcore_error.h"
+#include "wegl_platform.h"
+
+
+#ifdef WAFFLE_HAS_ANDROID
+static const char *libEGL_filename = "libEGL.so";
+#else
+static const char *libEGL_filename = "libEGL.so.1";
+#endif
+
+bool
+wegl_platform_teardown(struct wegl_platform *self)
+{
+ bool ok = true;
+ int error = 0;
+
+ if (self->eglHandle) {
+ error = dlclose(self->eglHandle);
+ if (error) {
+ ok = false;
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "dlclose(\"%s\") failed: %s",
+ libEGL_filename, dlerror());
+ }
+ }
+
+ ok &= wcore_platform_teardown(&self->wcore);
+ return ok;
+}
+bool
+wegl_platform_init(struct wegl_platform *self)
+{
+ bool ok;
+
+ ok = wcore_platform_init(&self->wcore);
+ if (!ok)
+ goto error;
+
+ self->eglHandle = dlopen(libEGL_filename, RTLD_LAZY | RTLD_LOCAL);
+ if (!self->eglHandle) {
+ wcore_errorf(WAFFLE_ERROR_FATAL,
+ "dlopen(\"%s\") failed: %s",
+ libEGL_filename, dlerror());
+ goto error;
+ }
+
+#define RETRIEVE_EGL_SYMBOL(function) \
+ self->function = dlsym(self->eglHandle, #function); \
+ if (!self->function) { \
+ wcore_errorf(WAFFLE_ERROR_FATAL, \
+ "dlsym(\"%s\", \"" #function "\") failed: %s", \
+ libEGL_filename, dlerror()); \
+ goto error; \
+ }
+
+ RETRIEVE_EGL_SYMBOL(eglMakeCurrent);
+ RETRIEVE_EGL_SYMBOL(eglGetProcAddress);
+
+ // display
+ RETRIEVE_EGL_SYMBOL(eglGetDisplay);
+ RETRIEVE_EGL_SYMBOL(eglInitialize);
+ RETRIEVE_EGL_SYMBOL(eglQueryString);
+ RETRIEVE_EGL_SYMBOL(eglGetError);
+ RETRIEVE_EGL_SYMBOL(eglTerminate);
+
+ // config
+ RETRIEVE_EGL_SYMBOL(eglChooseConfig);
+
+ // context
+ RETRIEVE_EGL_SYMBOL(eglBindAPI);
+ RETRIEVE_EGL_SYMBOL(eglCreateContext);
+ RETRIEVE_EGL_SYMBOL(eglDestroyContext);
+
+ // window
+ RETRIEVE_EGL_SYMBOL(eglGetConfigAttrib);
+ RETRIEVE_EGL_SYMBOL(eglCreateWindowSurface);
+ RETRIEVE_EGL_SYMBOL(eglDestroySurface);
+ RETRIEVE_EGL_SYMBOL(eglSwapBuffers);
+
+#undef RETRIEVE_EGL_SYMBOL
+
+error:
+ // On failure the caller of wegl_platform_init will trigger it's own
+ // destruction which will execute wegl_platform_teardown.
+ return ok;
+}
diff --git a/src/waffle/egl/wegl_platform.h b/src/waffle/egl/wegl_platform.h
new file mode 100644
index 0000000..645c3f8
--- /dev/null
+++ b/src/waffle/egl/wegl_platform.h
@@ -0,0 +1,82 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <EGL/egl.h>
+
+#include "wcore_platform.h"
+#include "wcore_util.h"
+
+struct wegl_platform {
+ struct wcore_platform wcore;
+
+ // EGL function pointers
+ void *eglHandle;
+
+ EGLBoolean (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx);
+ __eglMustCastToProperFunctionPointerType
+ (*eglGetProcAddress)(const char *procname);
+
+ // display
+ EGLDisplay (*eglGetDisplay)(EGLNativeDisplayType display_id);
+ EGLBoolean (*eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
+ const char * (*eglQueryString)(EGLDisplay dpy, EGLint name);
+ EGLint (*eglGetError)(void);
+ EGLBoolean (*eglTerminate)(EGLDisplay dpy);
+
+ // config
+ EGLBoolean (*eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config);
+
+ // context
+ EGLBoolean (*eglBindAPI)(EGLenum api);
+ EGLContext (*eglCreateContext)(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list);
+ EGLBoolean (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
+
+ // window
+ EGLBoolean (*eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value);
+ EGLSurface (*eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list);
+ EGLBoolean (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
+ EGLBoolean (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
+};
+
+DEFINE_CONTAINER_CAST_FUNC(wegl_platform,
+ struct wegl_platform,
+ struct wcore_platform,
+ wcore)
+
+bool
+wegl_platform_teardown(struct wegl_platform *self);
+
+bool
+wegl_platform_init(struct wegl_platform *self);
diff --git a/src/waffle/egl/wegl_util.c b/src/waffle/egl/wegl_util.c
index eb2415b..81fdbd9 100644
--- a/src/waffle/egl/wegl_util.c
+++ b/src/waffle/egl/wegl_util.c
@@ -28,13 +28,14 @@
#include "wegl_context.h"
#include "wegl_display.h"
#include "wegl_imports.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "wegl_window.h"
void
-wegl_emit_error(const char *egl_func_call)
+wegl_emit_error(struct wegl_platform *plat, const char *egl_func_call)
{
- EGLint egl_error_code = eglGetError();
+ EGLint egl_error_code = plat->eglGetError();
const char *egl_error_name;
switch (egl_error_code) {
@@ -74,17 +75,18 @@ wegl_make_current(struct wcore_platform *wc_plat,
struct wcore_window *wc_window,
struct wcore_context *wc_ctx)
{
- bool ok;
+ struct wegl_platform *plat = wegl_platform(wc_plat);
EGLSurface surface = wc_window ? wegl_window(wc_window)->egl : NULL;
+ bool ok;
- ok = eglMakeCurrent(wegl_display(wc_dpy)->egl,
- surface,
- surface,
- wc_ctx
- ? wegl_context(wc_ctx)->egl
- : NULL);
+ ok = plat->eglMakeCurrent(wegl_display(wc_dpy)->egl,
+ surface,
+ surface,
+ wc_ctx
+ ? wegl_context(wc_ctx)->egl
+ : NULL);
if (!ok)
- wegl_emit_error("eglMakeCurrent");
+ wegl_emit_error(plat, "eglMakeCurrent");
return ok;
}
@@ -92,5 +94,6 @@ wegl_make_current(struct wcore_platform *wc_plat,
void*
wegl_get_proc_address(struct wcore_platform *wc_self, const char *name)
{
- return eglGetProcAddress(name);
+ struct wegl_platform *self = wegl_platform(wc_self);
+ return self->eglGetProcAddress(name);
}
diff --git a/src/waffle/egl/wegl_util.h b/src/waffle/egl/wegl_util.h
index 772f71d..bb1692f 100644
--- a/src/waffle/egl/wegl_util.h
+++ b/src/waffle/egl/wegl_util.h
@@ -33,12 +33,13 @@
struct wcore_context;
struct wcore_display;
struct wcore_window;
+struct wegl_platform;
/// @brief Sets the waffle error with info from eglGetError().
/// @param egl_func_call Examples are "eglMakeCurrent()" and
/// "eglBindAPI(EGL_OPENGL_API)".
void
-wegl_emit_error(const char *egl_func_call);
+wegl_emit_error(struct wegl_platform *plat, const char *egl_func_call);
bool
wegl_make_current(struct wcore_platform *wc_plat,
diff --git a/src/waffle/egl/wegl_window.c b/src/waffle/egl/wegl_window.c
index e16b61d..753fd2f 100644
--- a/src/waffle/egl/wegl_window.c
+++ b/src/waffle/egl/wegl_window.c
@@ -26,6 +26,7 @@
#include "wegl_config.h"
#include "wegl_display.h"
#include "wegl_imports.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "wegl_window.h"
@@ -38,6 +39,7 @@ wegl_window_init(struct wegl_window *window,
{
struct wegl_config *config = wegl_config(wc_config);
struct wegl_display *dpy = wegl_display(wc_config->display);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
EGLint egl_render_buffer;
bool ok;
@@ -55,12 +57,13 @@ wegl_window_init(struct wegl_window *window,
EGL_NONE,
};
- window->egl = eglCreateWindowSurface(dpy->egl,
- config->egl,
- (EGLNativeWindowType) native_window,
- attrib_list);
+ window->egl = plat->eglCreateWindowSurface(dpy->egl,
+ config->egl,
+ (EGLNativeWindowType)
+ native_window,
+ attrib_list);
if (!window->egl) {
- wegl_emit_error("eglCreateWindowSurface");
+ wegl_emit_error(plat, "eglCreateWindowSurface");
goto fail;
}
@@ -75,12 +78,13 @@ bool
wegl_window_teardown(struct wegl_window *window)
{
struct wegl_display *dpy = wegl_display(window->wcore.display);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
bool result = true;
if (window->egl) {
- bool ok = eglDestroySurface(dpy->egl, window->egl);
+ bool ok = plat->eglDestroySurface(dpy->egl, window->egl);
if (!ok) {
- wegl_emit_error("eglDestroySurface");
+ wegl_emit_error(plat, "eglDestroySurface");
result = false;
}
}
@@ -94,10 +98,11 @@ wegl_window_swap_buffers(struct wcore_window *wc_window)
{
struct wegl_window *window = wegl_window(wc_window);
struct wegl_display *dpy = wegl_display(window->wcore.display);
+ struct wegl_platform *plat = wegl_platform(dpy->wcore.platform);
- bool ok = eglSwapBuffers(dpy->egl, window->egl);
+ bool ok = plat->eglSwapBuffers(dpy->egl, window->egl);
if (!ok)
- wegl_emit_error("eglSwapBuffers");
+ wegl_emit_error(plat, "eglSwapBuffers");
return ok;
}
diff --git a/src/waffle/gbm/wgbm_display.c b/src/waffle/gbm/wgbm_display.c
index 22a8e8a..76e6c32 100644
--- a/src/waffle/gbm/wgbm_display.c
+++ b/src/waffle/gbm/wgbm_display.c
@@ -23,14 +23,12 @@
// 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.
-#define __GBM__ 1
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
-#include <gbm.h>
#include <libudev.h>
#include <fcntl.h>
#include <sys/types.h>
@@ -46,6 +44,8 @@ bool
wgbm_display_destroy(struct wcore_display *wc_self)
{
struct wgbm_display *self = wgbm_display(wc_self);
+ struct wcore_platform *wc_plat = wc_self->platform;
+ struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat));
bool ok = true;
int fd;
@@ -56,8 +56,8 @@ wgbm_display_destroy(struct wcore_display *wc_self)
ok &= wegl_display_teardown(&self->wegl);
if (self->gbm_device) {
- fd = gbm_device_get_fd(self->gbm_device);
- gbm_device_destroy(self->gbm_device);
+ fd = plat->gbm_device_get_fd(self->gbm_device);
+ plat->gbm_device_destroy(self->gbm_device);
close(fd);
}
@@ -120,6 +120,7 @@ wgbm_display_connect(struct wcore_platform *wc_plat,
const char *name)
{
struct wgbm_display *self;
+ struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat));
bool ok = true;
int fd;
@@ -139,7 +140,7 @@ wgbm_display_connect(struct wcore_platform *wc_plat,
}
dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
- self->gbm_device = gbm_create_device(fd);
+ self->gbm_device = plat->gbm_create_device(fd);
if (!self->gbm_device) {
wcore_errorf(WAFFLE_ERROR_UNKNOWN, "gbm_create_device failed");
goto error;
diff --git a/src/waffle/gbm/wgbm_platform.c b/src/waffle/gbm/wgbm_platform.c
index d556145..981c366 100644
--- a/src/waffle/gbm/wgbm_platform.c
+++ b/src/waffle/gbm/wgbm_platform.c
@@ -23,10 +23,10 @@
// 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.
-#define __GBM__ 1
#define _POSIX_C_SOURCE 200112 // glib feature macro for unsetenv()
#include <stdlib.h>
+#include <dlfcn.h>
#include "wcore_error.h"
@@ -34,6 +34,7 @@
#include "wegl_config.h"
#include "wegl_context.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "wgbm_config.h"
@@ -41,13 +42,16 @@
#include "wgbm_platform.h"
#include "wgbm_window.h"
+static const char *libgbm_filename = "libgbm.so.1";
+
static const struct wcore_platform_vtbl wgbm_platform_vtbl;
static bool
wgbm_platform_destroy(struct wcore_platform *wc_self)
{
- struct wgbm_platform *self = wgbm_platform(wc_self);
+ struct wgbm_platform *self = wgbm_platform(wegl_platform(wc_self));
bool ok = true;
+ int error = 0;
if (!self)
return true;
@@ -57,7 +61,17 @@ wgbm_platform_destroy(struct wcore_platform *wc_self)
if (self->linux)
ok &= linux_platform_destroy(self->linux);
- ok &= wcore_platform_teardown(wc_self);
+ if (self->gbmHandle) {
+ error = dlclose(self->gbmHandle);
+ if (error) {
+ ok &= false;
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "dlclose(\"%s\") failed: %s",
+ libgbm_filename, dlerror());
+ }
+ }
+
+ ok &= wegl_platform_teardown(&self->wegl);
free(self);
return ok;
}
@@ -72,21 +86,49 @@ wgbm_platform_create(void)
if (self == NULL)
return NULL;
- ok = wcore_platform_init(&self->wcore);
+ ok = wegl_platform_init(&self->wegl);
if (!ok)
goto error;
+ self->gbmHandle = dlopen(libgbm_filename, RTLD_LAZY | RTLD_LOCAL);
+ if (!self->gbmHandle) {
+ wcore_errorf(WAFFLE_ERROR_FATAL,
+ "dlopen(\"%s\") failed: %s",
+ libgbm_filename, dlerror());
+ goto error;
+ }
+
+#define RETRIEVE_GBM_SYMBOL(function) \
+ self->function = dlsym(self->gbmHandle, #function); \
+ if (!self->function) { \
+ wcore_errorf(WAFFLE_ERROR_FATAL, \
+ "dlsym(\"%s\", \"" #function "\") failed: %s", \
+ libgbm_filename, dlerror()); \
+ goto error; \
+ }
+
+ RETRIEVE_GBM_SYMBOL(gbm_create_device);
+ RETRIEVE_GBM_SYMBOL(gbm_device_get_fd);
+ RETRIEVE_GBM_SYMBOL(gbm_device_destroy);
+
+ RETRIEVE_GBM_SYMBOL(gbm_surface_create);
+ RETRIEVE_GBM_SYMBOL(gbm_surface_destroy);
+
+ RETRIEVE_GBM_SYMBOL(gbm_surface_lock_front_buffer);
+ RETRIEVE_GBM_SYMBOL(gbm_surface_release_buffer);
+#undef RETRIEVE_GBM_SYMBOL
+
self->linux = linux_platform_create();
if (!self->linux)
goto error;
setenv("EGL_PLATFORM", "drm", true);
- self->wcore.vtbl = &wgbm_platform_vtbl;
- return &self->wcore;
+ self->wegl.wcore.vtbl = &wgbm_platform_vtbl;
+ return &self->wegl.wcore;
error:
- wgbm_platform_destroy(&self->wcore);
+ wgbm_platform_destroy(&self->wegl.wcore);
return NULL;
}
@@ -94,8 +136,8 @@ static bool
wgbm_dl_can_open(struct wcore_platform *wc_self,
int32_t waffle_dl)
{
- return linux_platform_dl_can_open(wgbm_platform(wc_self)->linux,
- waffle_dl);
+ struct wgbm_platform *self = wgbm_platform(wegl_platform(wc_self));
+ return linux_platform_dl_can_open(self->linux, waffle_dl);
}
static void*
@@ -103,9 +145,8 @@ wgbm_dl_sym(struct wcore_platform *wc_self,
int32_t waffle_dl,
const char *name)
{
- return linux_platform_dl_sym(wgbm_platform(wc_self)->linux,
- waffle_dl,
- name);
+ struct wgbm_platform *self = wgbm_platform(wegl_platform(wc_self));
+ return linux_platform_dl_sym(self->linux, waffle_dl, name);
}
static union waffle_native_context*
diff --git a/src/waffle/gbm/wgbm_platform.h b/src/waffle/gbm/wgbm_platform.h
index c833780..259eb19 100644
--- a/src/waffle/gbm/wgbm_platform.h
+++ b/src/waffle/gbm/wgbm_platform.h
@@ -27,23 +27,40 @@
#include <stdbool.h>
#include <stdlib.h>
+#include <gbm.h>
#undef linux
-#include "wcore_platform.h"
+#include "wegl_platform.h"
#include "wcore_util.h"
struct linux_platform;
struct wgbm_platform {
- struct wcore_platform wcore;
+ struct wegl_platform wegl;
struct linux_platform *linux;
+
+ // GBM function pointers
+ void *gbmHandle;
+
+ struct gbm_device *(*gbm_create_device)(int fd);
+ int (*gbm_device_get_fd)(struct gbm_device *gbm);
+ void (*gbm_device_destroy)(struct gbm_device *gbm);
+
+ struct gbm_surface *(*gbm_surface_create)(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags);
+ void (*gbm_surface_destroy)(struct gbm_surface *surface);
+
+ struct gbm_bo *(*gbm_surface_lock_front_buffer)(struct gbm_surface *surface);
+ void (*gbm_surface_release_buffer)(struct gbm_surface *surface,
+ struct gbm_bo *bo);
};
DEFINE_CONTAINER_CAST_FUNC(wgbm_platform,
struct wgbm_platform,
- struct wcore_platform,
- wcore)
+ struct wegl_platform,
+ wegl)
struct wcore_platform*
wgbm_platform_create(void);
diff --git a/src/waffle/gbm/wgbm_window.c b/src/waffle/gbm/wgbm_window.c
index bce32a4..edac449 100644
--- a/src/waffle/gbm/wgbm_window.c
+++ b/src/waffle/gbm/wgbm_window.c
@@ -23,8 +23,6 @@
// 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.
-#define __GBM__ 1
-
#include <stdlib.h>
#include <string.h>
@@ -38,11 +36,14 @@
#include "wgbm_config.h"
#include "wgbm_display.h"
+#include "wgbm_platform.h"
#include "wgbm_window.h"
bool
wgbm_window_destroy(struct wcore_window *wc_self)
{
+ struct wcore_platform *wc_plat = wc_self->display->platform;
+ struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat));
struct wgbm_window *self = wgbm_window(wc_self);
bool ok = true;
@@ -50,7 +51,7 @@ wgbm_window_destroy(struct wcore_window *wc_self)
return ok;
ok &= wegl_window_teardown(&self->wegl);
- gbm_surface_destroy(self->gbm_surface);
+ plat->gbm_surface_destroy(self->gbm_surface);
free(self);
return ok;
}
@@ -61,8 +62,9 @@ wgbm_window_create(struct wcore_platform *wc_plat,
int width,
int height)
{
- struct wgbm_window *self;
struct wgbm_display *dpy = wgbm_display(wc_config->display);
+ struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat));
+ struct wgbm_window *self;
uint32_t gbm_format;
bool ok = true;
@@ -72,9 +74,9 @@ wgbm_window_create(struct wcore_platform *wc_plat,
gbm_format = wgbm_config_get_gbm_format(&wc_config->attrs);
assert(gbm_format != 0);
- self->gbm_surface = gbm_surface_create(dpy->gbm_device, width, height,
- gbm_format,
- GBM_BO_USE_RENDERING);
+ self->gbm_surface = plat->gbm_surface_create(dpy->gbm_device,
+ width, height, gbm_format,
+ GBM_BO_USE_RENDERING);
if (!self->gbm_surface) {
wcore_errorf(WAFFLE_ERROR_UNKNOWN,
"gbm_surface_create failed");
@@ -104,15 +106,18 @@ wgbm_window_show(struct wcore_window *wc_self)
bool
wgbm_window_swap_buffers(struct wcore_window *wc_self)
{
+ struct wcore_platform *wc_plat = wc_self->display->platform;
+ struct wgbm_platform *plat = wgbm_platform(wegl_platform(wc_plat));
+
if (!wegl_window_swap_buffers(wc_self))
return false;
struct wgbm_window *self = wgbm_window(wc_self);
- struct gbm_bo *bo = gbm_surface_lock_front_buffer(self->gbm_surface);
+ struct gbm_bo *bo = plat->gbm_surface_lock_front_buffer(self->gbm_surface);
if (!bo)
return false;
- gbm_surface_release_buffer(self->gbm_surface, bo);
+ plat->gbm_surface_release_buffer(self->gbm_surface, bo);
return true;
}
diff --git a/src/waffle/gbm/wgbm_window.h b/src/waffle/gbm/wgbm_window.h
index 0a895db..729612b 100644
--- a/src/waffle/gbm/wgbm_window.h
+++ b/src/waffle/gbm/wgbm_window.h
@@ -30,6 +30,7 @@
#include "wegl_window.h"
struct wcore_platform;
+struct gbm_surface;
struct wgbm_window {
struct gbm_surface *gbm_surface;
diff --git a/src/waffle/glx/glx_config.c b/src/waffle/glx/glx_config.c
index e077b07..7792aa0 100644
--- a/src/waffle/glx/glx_config.c
+++ b/src/waffle/glx/glx_config.c
@@ -170,6 +170,7 @@ glx_config_choose(struct wcore_platform *wc_plat,
{
struct glx_config *self;
struct glx_display *dpy = glx_display(wc_dpy);
+ struct glx_platform *plat = glx_platform(wc_plat);
GLXFBConfig *configs = NULL;
int num_configs = 0;
@@ -222,7 +223,7 @@ glx_config_choose(struct wcore_platform *wc_plat,
};
// Set glx_fbconfig.
- configs = wrapped_glXChooseFBConfig(dpy->x11.xlib,
+ configs = wrapped_glXChooseFBConfig(plat, dpy->x11.xlib,
dpy->x11.screen,
attrib_list,
&num_configs);
@@ -235,7 +236,7 @@ glx_config_choose(struct wcore_platform *wc_plat,
self->glx_fbconfig = configs[0];
// Set glx_fbconfig_id.
- ok = !wrapped_glXGetFBConfigAttrib(dpy->x11.xlib,
+ ok = !wrapped_glXGetFBConfigAttrib(plat, dpy->x11.xlib,
self->glx_fbconfig,
GLX_FBCONFIG_ID,
&self->glx_fbconfig_id);
@@ -245,7 +246,7 @@ glx_config_choose(struct wcore_platform *wc_plat,
}
// Set xcb_visual_id.
- vi = wrapped_glXGetVisualFromFBConfig(dpy->x11.xlib,
+ vi = wrapped_glXGetVisualFromFBConfig(plat, dpy->x11.xlib,
self->glx_fbconfig);
if (!vi) {
wcore_errorf(WAFFLE_ERROR_UNKNOWN,
diff --git a/src/waffle/glx/glx_context.c b/src/waffle/glx/glx_context.c
index 62573dc..57db2ba 100644
--- a/src/waffle/glx/glx_context.c
+++ b/src/waffle/glx/glx_context.c
@@ -45,6 +45,7 @@ glx_context_destroy(struct wcore_context *wc_self)
{
struct glx_context *self;
struct glx_display *dpy;
+ struct glx_platform *platform;
bool ok = true;
if (!wc_self)
@@ -52,9 +53,10 @@ glx_context_destroy(struct wcore_context *wc_self)
self = glx_context(wc_self);
dpy = glx_display(wc_self->display);
+ platform = glx_platform(wc_self->display->platform);
if (self->glx)
- wrapped_glXDestroyContext(dpy->x11.xlib, self->glx);
+ wrapped_glXDestroyContext(platform, dpy->x11.xlib, self->glx);
ok &= wcore_context_teardown(wc_self);
free(self);
@@ -182,7 +184,8 @@ glx_context_create_native(struct glx_config *config,
}
}
else {
- ctx = wrapped_glXCreateNewContext(dpy->x11.xlib,
+ ctx = wrapped_glXCreateNewContext(platform,
+ dpy->x11.xlib,
config->glx_fbconfig,
GLX_RGBA_TYPE,
real_share_ctx,
diff --git a/src/waffle/glx/glx_display.c b/src/waffle/glx/glx_display.c
index 184438f..567d442 100644
--- a/src/waffle/glx/glx_display.c
+++ b/src/waffle/glx/glx_display.c
@@ -51,8 +51,9 @@ glx_display_destroy(struct wcore_display *wc_self)
static bool
glx_display_set_extensions(struct glx_display *self)
{
-
- const char *s = wrapped_glXQueryExtensionsString(self->x11.xlib,
+ struct glx_platform *platform = glx_platform(self->wcore.platform);
+ const char *s = wrapped_glXQueryExtensionsString(platform,
+ self->x11.xlib,
self->x11.screen);
if (!s) {
wcore_errorf(WAFFLE_ERROR_UNKNOWN,
diff --git a/src/waffle/glx/glx_platform.c b/src/waffle/glx/glx_platform.c
index 804c275..4fb2eed 100644
--- a/src/waffle/glx/glx_platform.c
+++ b/src/waffle/glx/glx_platform.c
@@ -24,6 +24,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
+#include <dlfcn.h>
#include "wcore_error.h"
@@ -36,6 +37,8 @@
#include "glx_window.h"
#include "glx_wrappers.h"
+static const char *libGL_filename = "libGL.so.1";
+
static const struct wcore_platform_vtbl glx_platform_vtbl;
static bool
@@ -43,6 +46,7 @@ glx_platform_destroy(struct wcore_platform *wc_self)
{
struct glx_platform *self = glx_platform(wc_self);
bool ok = true;
+ int error = 0;
if (!self)
return true;
@@ -50,6 +54,16 @@ glx_platform_destroy(struct wcore_platform *wc_self)
if (self->linux)
ok &= linux_platform_destroy(self->linux);
+ if (self->glxHandle) {
+ error = dlclose(self->glxHandle);
+ if (error) {
+ ok &= false;
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "dlclose(\"%s\") failed: %s",
+ libGL_filename, dlerror());
+ }
+ }
+
ok &= wcore_platform_teardown(wc_self);
free(self);
return ok;
@@ -69,11 +83,42 @@ glx_platform_create(void)
if (!ok)
goto error;
+ self->glxHandle = dlopen(libGL_filename, RTLD_LAZY | RTLD_LOCAL);
+ if (!self->glxHandle) {
+ wcore_errorf(WAFFLE_ERROR_FATAL,
+ "dlopen(\"%s\") failed: %s",
+ libGL_filename, dlerror());
+ goto error;
+ }
+
+#define RETRIEVE_GLX_SYMBOL(function) \
+ self->function = dlsym(self->glxHandle, #function); \
+ if (!self->function) { \
+ wcore_errorf(WAFFLE_ERROR_FATAL, \
+ "dlsym(\"%s\", \"" #function "\") failed: %s", \
+ libGL_filename, dlerror()); \
+ goto error; \
+ }
+
+ RETRIEVE_GLX_SYMBOL(glXCreateNewContext);
+ RETRIEVE_GLX_SYMBOL(glXDestroyContext);
+ RETRIEVE_GLX_SYMBOL(glXMakeCurrent);
+
+ RETRIEVE_GLX_SYMBOL(glXQueryExtensionsString);
+ RETRIEVE_GLX_SYMBOL(glXGetProcAddress);
+
+ RETRIEVE_GLX_SYMBOL(glXGetVisualFromFBConfig);
+ RETRIEVE_GLX_SYMBOL(glXGetFBConfigAttrib);
+ RETRIEVE_GLX_SYMBOL(glXChooseFBConfig);
+
+ RETRIEVE_GLX_SYMBOL(glXSwapBuffers);
+#undef RETRIEVE_GLX_SYMBOL
+
self->linux = linux_platform_create();
if (!self->linux)
goto error;
- self->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const uint8_t*) "glXCreateContextAttribsARB");
+ self->glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) self->glXGetProcAddress((const uint8_t*) "glXCreateContextAttribsARB");
self->wcore.vtbl = &glx_platform_vtbl;
return &self->wcore;
@@ -89,12 +134,13 @@ glx_platform_make_current(struct wcore_platform *wc_self,
struct wcore_window *wc_window,
struct wcore_context *wc_ctx)
{
- bool ok;
+ struct glx_platform *self = glx_platform(wc_self);
Display *dpy = glx_display(wc_dpy)->x11.xlib;
GLXDrawable win = wc_window ? glx_window(wc_window)->x11.xcb : 0;
GLXContext ctx = wc_ctx ? glx_context(wc_ctx)->glx : NULL;
-
- ok = wrapped_glXMakeCurrent(dpy, win, ctx);
+ bool ok;
+
+ ok = wrapped_glXMakeCurrent(self, dpy, win, ctx);
if (!ok) {
wcore_errorf(WAFFLE_ERROR_UNKNOWN, "glXMakeCurrent failed");
}
@@ -106,7 +152,8 @@ static void*
glx_platform_get_proc_address(struct wcore_platform *wc_self,
const char *name)
{
- return glXGetProcAddress((const GLubyte*) name);
+ struct glx_platform *self = glx_platform(wc_self);
+ return self->glXGetProcAddress((const GLubyte*) name);
}
static bool
diff --git a/src/waffle/glx/glx_platform.h b/src/waffle/glx/glx_platform.h
index 58519e8..36ddff6 100644
--- a/src/waffle/glx/glx_platform.h
+++ b/src/waffle/glx/glx_platform.h
@@ -26,12 +26,8 @@
#pragma once
#include <GL/glx.h>
-#include <X11/Xlib.h>
-#include <xcb/xcb.h>
#undef linux
-#include "waffle_glx.h"
-
#include "wcore_platform.h"
#include "wcore_util.h"
@@ -41,6 +37,27 @@ struct glx_platform {
struct wcore_platform wcore;
struct linux_platform *linux;
+ // glX function pointers
+ void *glxHandle;
+
+ GLXContext (*glXCreateNewContext)(Display *dpy, GLXFBConfig config,
+ int renderType, GLXContext shareList,
+ Bool direct);
+ void (*glXDestroyContext)(Display *dpy, GLXContext ctx);
+ Bool (*glXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx);
+
+ const char *(*glXQueryExtensionsString)(Display *dpy, int screen);
+ void *(*glXGetProcAddress)(const GLubyte *procname);
+
+ XVisualInfo *(*glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config);
+ int (*glXGetFBConfigAttrib)(Display *dpy, GLXFBConfig config,
+ int attribute, int *value);
+ GLXFBConfig *(*glXChooseFBConfig)(Display *dpy, int screen,
+ const int *attribList, int *nitems);
+
+ void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable);
+
+
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
};
diff --git a/src/waffle/glx/glx_window.c b/src/waffle/glx/glx_window.c
index 702ed3f..34fa784 100644
--- a/src/waffle/glx/glx_window.c
+++ b/src/waffle/glx/glx_window.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
+#include <xcb/xcb.h>
#include "wcore_error.h"
@@ -100,8 +101,9 @@ glx_window_swap_buffers(struct wcore_window *wc_self)
{
struct glx_window *self = glx_window(wc_self);
struct glx_display *dpy = glx_display(wc_self->display);
+ struct glx_platform *plat = glx_platform(wc_self->display->platform);
- wrapped_glXSwapBuffers(dpy->x11.xlib, self->x11.xcb);
+ wrapped_glXSwapBuffers(plat, dpy->x11.xlib, self->x11.xcb);
return true;
}
diff --git a/src/waffle/glx/glx_window.h b/src/waffle/glx/glx_window.h
index 4cf44e3..5aed497 100644
--- a/src/waffle/glx/glx_window.h
+++ b/src/waffle/glx/glx_window.h
@@ -27,8 +27,6 @@
#include <stdbool.h>
-#include <xcb/xcb.h>
-
#include "wcore_window.h"
#include "wcore_util.h"
diff --git a/src/waffle/glx/glx_wrappers.h b/src/waffle/glx/glx_wrappers.h
index 5f53332..1411c86 100644
--- a/src/waffle/glx/glx_wrappers.h
+++ b/src/waffle/glx/glx_wrappers.h
@@ -45,19 +45,22 @@
#include "x11_wrappers.h"
static inline GLXFBConfig*
-wrapped_glXChooseFBConfig(Display *dpy, int screen,
+wrapped_glXChooseFBConfig(struct glx_platform *platform,
+ Display *dpy, int screen,
const int *attribList, int *nitems)
{
X11_SAVE_ERROR_HANDLER
- GLXFBConfig *configs = glXChooseFBConfig(dpy, screen, attribList, nitems);
+ GLXFBConfig *configs = platform->glXChooseFBConfig(dpy, screen,
+ attribList, nitems);
X11_RESTORE_ERROR_HANDLER
return configs;
}
static inline GLXContext
-wrapped_glXCreateContextAttribsARB(
- struct glx_platform *platform, Display *dpy, GLXFBConfig config,
- GLXContext share_context, Bool direct, const int *attrib_list)
+wrapped_glXCreateContextAttribsARB(struct glx_platform *platform,
+ Display *dpy, GLXFBConfig config,
+ GLXContext share_context, Bool direct,
+ const int *attrib_list)
{
X11_SAVE_ERROR_HANDLER
GLXContext ctx = platform->glXCreateContextAttribsARB(
@@ -67,65 +70,72 @@ wrapped_glXCreateContextAttribsARB(
}
static inline GLXContext
-wrapped_glXCreateNewContext(Display *dpy, GLXFBConfig config, int renderType,
+wrapped_glXCreateNewContext(struct glx_platform *platform,
+ Display *dpy, GLXFBConfig config, int renderType,
GLXContext shareList, Bool direct)
{
X11_SAVE_ERROR_HANDLER
- GLXContext ctx = glXCreateNewContext(dpy, config, renderType, shareList,
- direct);
+ GLXContext ctx = platform->glXCreateNewContext(dpy, config, renderType,
+ shareList, direct);
X11_RESTORE_ERROR_HANDLER
return ctx;
}
static inline int
-wrapped_glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config,
+wrapped_glXGetFBConfigAttrib(struct glx_platform *platform,
+ Display *dpy, GLXFBConfig config,
int attribute, int *value)
{
X11_SAVE_ERROR_HANDLER
- int error = glXGetFBConfigAttrib(dpy, config, attribute, value);
+ int error = platform->glXGetFBConfigAttrib(dpy, config, attribute, value);
X11_RESTORE_ERROR_HANDLER
return error;
}
static inline XVisualInfo*
-wrapped_glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
+wrapped_glXGetVisualFromFBConfig(struct glx_platform *platform,
+ Display *dpy, GLXFBConfig config)
{
X11_SAVE_ERROR_HANDLER
- XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, config);
+ XVisualInfo *vi = platform->glXGetVisualFromFBConfig(dpy, config);
X11_RESTORE_ERROR_HANDLER
return vi;
}
static inline void
-wrapped_glXDestroyContext(Display *dpy, GLXContext ctx)
+wrapped_glXDestroyContext(struct glx_platform *platform,
+ Display *dpy, GLXContext ctx)
{
X11_SAVE_ERROR_HANDLER
- glXDestroyContext(dpy, ctx);
+ platform->glXDestroyContext(dpy, ctx);
X11_RESTORE_ERROR_HANDLER
}
static inline Bool
-wrapped_glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx)
+wrapped_glXMakeCurrent(struct glx_platform *platform,
+ Display *dpy, GLXDrawable drawable, GLXContext ctx)
{
X11_SAVE_ERROR_HANDLER
- Bool ok = glXMakeCurrent(dpy, drawable, ctx);
+ Bool ok = platform->glXMakeCurrent(dpy, drawable, ctx);
X11_RESTORE_ERROR_HANDLER
return ok;
}
static inline const char*
-wrapped_glXQueryExtensionsString(Display *dpy, int screen)
+wrapped_glXQueryExtensionsString(struct glx_platform *platform,
+ Display *dpy, int screen)
{
X11_SAVE_ERROR_HANDLER
- const char *s = glXQueryExtensionsString(dpy, screen);
+ const char *s = platform->glXQueryExtensionsString(dpy, screen);
X11_RESTORE_ERROR_HANDLER
return s;
}
static inline void
-wrapped_glXSwapBuffers(Display *dpy, GLXDrawable drawable)
+wrapped_glXSwapBuffers(struct glx_platform *platform,
+ Display *dpy, GLXDrawable drawable)
{
X11_SAVE_ERROR_HANDLER
- glXSwapBuffers(dpy, drawable);
+ platform->glXSwapBuffers(dpy, drawable);
X11_RESTORE_ERROR_HANDLER
}
diff --git a/src/waffle/waffle.def.in b/src/waffle/waffle.def.in
new file mode 100644
index 0000000..db8464f
--- /dev/null
+++ b/src/waffle/waffle.def.in
@@ -0,0 +1,33 @@
+LIBRARY @waffle_libname@
+
+EXPORTS
+ waffle_error_get_code
+ waffle_error_get_info
+ waffle_error_to_string
+ waffle_enum_to_string
+ waffle_init
+ waffle_make_current
+ waffle_get_proc_address
+ waffle_is_extension_in_string
+ waffle_display_connect
+ waffle_display_disconnect
+ waffle_display_supports_context_api
+ waffle_display_get_native
+ waffle_config_choose
+ waffle_config_destroy
+ waffle_config_get_native
+ waffle_context_create
+ waffle_context_destroy
+ waffle_context_get_native
+ waffle_window_create
+ waffle_window_destroy
+ waffle_window_show
+ waffle_window_swap_buffers
+ waffle_window_get_native
+ waffle_window_resize
+ waffle_dl_can_open
+ waffle_dl_sym
+ waffle_attrib_list_length
+ waffle_attrib_list_get
+ waffle_attrib_list_get_with_default
+ waffle_attrib_list_update \ No newline at end of file
diff --git a/src/waffle/wayland/wayland_platform.c b/src/waffle/wayland/wayland_platform.c
index 8ca30d4..63cfdc2 100644
--- a/src/waffle/wayland/wayland_platform.c
+++ b/src/waffle/wayland/wayland_platform.c
@@ -36,6 +36,7 @@
#include "wegl_config.h"
#include "wegl_context.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "wayland_display.h"
@@ -47,7 +48,7 @@ static const struct wcore_platform_vtbl wayland_platform_vtbl;
static bool
wayland_platform_destroy(struct wcore_platform *wc_self)
{
- struct wayland_platform *self = wayland_platform(wc_self);
+ struct wayland_platform *self = wayland_platform(wegl_platform(wc_self));
bool ok = true;
if (!self)
@@ -58,7 +59,7 @@ wayland_platform_destroy(struct wcore_platform *wc_self)
if (self->linux)
ok &= linux_platform_destroy(self->linux);
- ok &= wcore_platform_teardown(wc_self);
+ ok &= wegl_platform_teardown(&self->wegl);
free(self);
return ok;
}
@@ -73,7 +74,7 @@ wayland_platform_create(void)
if (self == NULL)
return NULL;
- ok = wcore_platform_init(&self->wcore);
+ ok = wegl_platform_init(&self->wegl);
if (!ok)
goto error;
@@ -83,11 +84,11 @@ wayland_platform_create(void)
setenv("EGL_PLATFORM", "wayland", true);
- self->wcore.vtbl = &wayland_platform_vtbl;
- return &self->wcore;
+ self->wegl.wcore.vtbl = &wayland_platform_vtbl;
+ return &self->wegl.wcore;
error:
- wayland_platform_destroy(&self->wcore);
+ wayland_platform_destroy(&self->wegl.wcore);
return NULL;
}
@@ -95,8 +96,8 @@ static bool
wayland_dl_can_open(struct wcore_platform *wc_self,
int32_t waffle_dl)
{
- return linux_platform_dl_can_open(wayland_platform(wc_self)->linux,
- waffle_dl);
+ struct wayland_platform *self = wayland_platform(wegl_platform(wc_self));
+ return linux_platform_dl_can_open(self->linux, waffle_dl);
}
static void*
@@ -104,9 +105,8 @@ wayland_dl_sym(struct wcore_platform *wc_self,
int32_t waffle_dl,
const char *name)
{
- return linux_platform_dl_sym(wayland_platform(wc_self)->linux,
- waffle_dl,
- name);
+ struct wayland_platform *self = wayland_platform(wegl_platform(wc_self));
+ return linux_platform_dl_sym(self->linux, waffle_dl, name);
}
static union waffle_native_config*
diff --git a/src/waffle/wayland/wayland_platform.h b/src/waffle/wayland/wayland_platform.h
index 41ca8f5..c4e870f 100644
--- a/src/waffle/wayland/wayland_platform.h
+++ b/src/waffle/wayland/wayland_platform.h
@@ -32,20 +32,20 @@
#include "waffle_wayland.h"
-#include "wcore_platform.h"
+#include "wegl_platform.h"
#include "wcore_util.h"
struct linux_platform;
struct wayland_platform {
- struct wcore_platform wcore;
+ struct wegl_platform wegl;
struct linux_platform *linux;
};
DEFINE_CONTAINER_CAST_FUNC(wayland_platform,
struct wayland_platform,
- struct wcore_platform,
- wcore)
+ struct wegl_platform,
+ wegl)
struct wcore_platform*
wayland_platform_create(void);
diff --git a/src/waffle/wgl/wgl_config.c b/src/waffle/wgl/wgl_config.c
new file mode 100644
index 0000000..59a70a6
--- /dev/null
+++ b/src/waffle/wgl/wgl_config.c
@@ -0,0 +1,302 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+#include "wcore_config_attrs.h"
+#include "wcore_error.h"
+
+#include "wgl_config.h"
+#include "wgl_display.h"
+#include "wgl_error.h"
+#include "wgl_platform.h"
+#include "wgl_window.h"
+
+bool
+wgl_config_destroy(struct wcore_config *wc_self)
+{
+ struct wgl_config *self = wgl_config(wc_self);
+ bool ok = true;
+
+ if (!self)
+ return true;
+
+ if (self->window)
+ ok &= wgl_window_priv_destroy(&self->window->wcore);
+
+ ok &= wcore_config_teardown(wc_self);
+ free(self);
+ return ok;
+}
+
+/// @brief Check the values of `attrs->context_*`.
+static bool
+wgl_config_check_context_attrs(struct wgl_display *dpy,
+ const struct wcore_config_attrs *attrs)
+{
+ if (attrs->context_forward_compatible) {
+ assert(attrs->context_api == WAFFLE_CONTEXT_OPENGL);
+ assert(wcore_config_attrs_version_ge(attrs, 30));
+ }
+
+ if (attrs->context_debug && !dpy->ARB_create_context) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_ARB_create_context is required in order to "
+ "request a debug context");
+ return false;
+ }
+
+ switch (attrs->context_api) {
+ case WAFFLE_CONTEXT_OPENGL:
+ if (!wcore_config_attrs_version_eq(attrs, 10) && !dpy->ARB_create_context) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_ARB_create_context is required in order to "
+ "request an OpenGL version not equal to the default "
+ "value 1.0");
+ return false;
+ }
+ else if (wcore_config_attrs_version_ge(attrs, 32) && !dpy->ARB_create_context_profile) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_ARB_create_context_profile is required "
+ "to create a context with version >= 3.2");
+ return false;
+ }
+ else if (wcore_config_attrs_version_ge(attrs, 32)) {
+ assert(attrs->context_profile == WAFFLE_CONTEXT_CORE_PROFILE ||
+ attrs->context_profile == WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ }
+
+ if (attrs->context_forward_compatible && !dpy->ARB_create_context) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_ARB_create_context is required in order to "
+ "request a forward-compatible context");
+ return false;
+ }
+
+ return true;
+
+ case WAFFLE_CONTEXT_OPENGL_ES1:
+ assert(wcore_config_attrs_version_eq(attrs, 10) ||
+ wcore_config_attrs_version_eq(attrs, 11));
+ assert(!attrs->context_forward_compatible);
+
+ if (!dpy->EXT_create_context_es_profile) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_EXT_create_context_es_profile is required "
+ "to create an OpenGL ES1 context");
+ return false;
+ }
+
+ return true;
+
+ case WAFFLE_CONTEXT_OPENGL_ES2:
+ assert(attrs->context_major_version == 2);
+ assert(!attrs->context_forward_compatible);
+
+ if (!dpy->EXT_create_context_es2_profile
+ && !dpy->EXT_create_context_es_profile) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_EXT_create_context_es_profile or "
+ "WGL_EXT_create_context_es2_profile is required "
+ "to create an OpenGL ES2 context");
+ return false;
+ }
+
+ return true;
+
+ case WAFFLE_CONTEXT_OPENGL_ES3:
+ assert(attrs->context_major_version == 3);
+
+ if (!dpy->EXT_create_context_es_profile) {
+ wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+ "WGL_EXT_create_context_es_profile is required "
+ "to create an OpenGL ES3 context");
+ return false;
+ }
+
+ return true;
+
+ default:
+ wcore_error_internal("context_api has bad value %#x",
+ attrs->context_api);
+ return false;
+ }
+}
+
+static void
+wgl_config_set_pixeldescriptor(struct wgl_config *config,
+ const struct wcore_config_attrs *attrs)
+{
+ PIXELFORMATDESCRIPTOR *pfd = &config->pfd;
+
+ pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pfd->nVersion = 1;
+
+ pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+ if (attrs->double_buffered)
+ pfd->dwFlags |= PFD_DOUBLEBUFFER;
+
+ pfd->iPixelType = PFD_TYPE_RGBA;
+
+ pfd->cColorBits = attrs->rgba_size;
+ pfd->cRedBits = attrs->red_size;
+ pfd->cGreenBits = attrs->green_size;
+ pfd->cBlueBits = attrs->blue_size;
+ pfd->cAlphaBits = attrs->alpha_size;
+
+ pfd->cDepthBits = attrs->depth_size;
+ pfd->cStencilBits = attrs->stencil_size;
+
+ // XXX: Double check these
+ pfd->cAccumRedBits = attrs->accum_buffer;
+ pfd->cAccumGreenBits = attrs->accum_buffer;
+ pfd->cAccumBlueBits = attrs->accum_buffer;
+ pfd->cAccumAlphaBits = attrs->accum_buffer;
+ pfd->cAccumBits = pfd->cAccumRedBits +
+ pfd->cAccumGreenBits +
+ pfd->cAccumBlueBits +
+ pfd->cAccumAlphaBits;
+
+ pfd->iLayerType = PFD_MAIN_PLANE;
+}
+
+static bool
+wgl_config_choose_native(struct wgl_config *config,
+ struct wgl_display *dpy,
+ const struct wcore_config_attrs *attrs)
+{
+
+ // Use wglChoosePixelFormatARB if available.
+ if (dpy->ARB_pixel_format) {
+ float fAttribs[1] = { 0 };
+ int iAttribs[] = {
+ WGL_COLOR_BITS_ARB, attrs->rgba_size,
+ WGL_RED_BITS_ARB, attrs->red_size,
+ WGL_GREEN_BITS_ARB, attrs->green_size,
+ WGL_BLUE_BITS_ARB, attrs->blue_size,
+ WGL_ALPHA_BITS_ARB, attrs->alpha_size,
+
+ WGL_DEPTH_BITS_ARB, attrs->depth_size,
+ WGL_STENCIL_BITS_ARB, attrs->stencil_size,
+
+ WGL_SAMPLE_BUFFERS_ARB, attrs->sample_buffers,
+ WGL_STEREO_ARB, attrs->samples,
+
+ WGL_DOUBLE_BUFFER_ARB, attrs->double_buffered,
+
+ WGL_ACCUM_RED_BITS_ARB, attrs->accum_buffer,
+ WGL_ACCUM_GREEN_BITS_ARB, attrs->accum_buffer,
+ WGL_ACCUM_BLUE_BITS_ARB, attrs->accum_buffer,
+ WGL_ACCUM_ALPHA_BITS_ARB, attrs->accum_buffer,
+
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+
+ 0,
+ };
+ unsigned int num_formats;
+ bool ok;
+
+ // But first we need a current context to use it...
+ ok = wglMakeCurrent(dpy->hDC, dpy->hglrc);
+ if (!ok)
+ return false;
+
+ ok = dpy->wglChoosePixelFormatARB(dpy->hDC, iAttribs, fAttribs, 1,
+ &config->pixel_format, &num_formats);
+
+ wglMakeCurrent(NULL, NULL);
+
+ if (!ok || !num_formats) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglChoosePixelFormatARB failed");
+ return false;
+ }
+
+ }
+ else {
+ config->pixel_format = ChoosePixelFormat(dpy->hDC, &config->pfd);
+ if (!config->pixel_format) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "ChoosePixelFormat failed to find a matching format");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+struct wcore_config*
+wgl_config_choose(struct wcore_platform *wc_plat,
+ struct wcore_display *wc_dpy,
+ const struct wcore_config_attrs *attrs)
+{
+ struct wgl_config *self;
+ struct wgl_display *dpy = wgl_display(wc_dpy);
+ struct wcore_window *wc_window;
+ bool ok;
+
+ ok = wgl_config_check_context_attrs(dpy, attrs);
+ if (!ok)
+ return NULL;
+
+ self = wcore_calloc(sizeof(*self));
+ if (!self)
+ return NULL;
+
+ ok = wcore_config_init(&self->wcore, wc_dpy, attrs);
+ if (!ok)
+ goto error;
+
+ wgl_config_set_pixeldescriptor(self, attrs);
+
+ ok = wgl_config_choose_native(self, dpy, attrs);
+ if (!ok)
+ goto error;
+
+ // Hurray, we've got the pixel format.
+
+ wc_window = wgl_window_priv_create(wc_plat, &self->wcore, 10, 10);
+ if (!wc_window)
+ goto error;
+
+ self->window = wgl_window(wc_window);
+
+ // Now let's pray that the root window's hDC is compatible with the
+ // new window hDC.
+ ok = SetPixelFormat(self->window->hDC, self->pixel_format, &self->pfd);
+ if (!ok)
+ goto error;
+
+ return &self->wcore;
+
+error:
+ wgl_config_destroy(&self->wcore);
+ return NULL;
+}
diff --git a/src/waffle/wgl/wgl_config.h b/src/waffle/wgl/wgl_config.h
new file mode 100644
index 0000000..77f8905
--- /dev/null
+++ b/src/waffle/wgl/wgl_config.h
@@ -0,0 +1,61 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+#include "wcore_config.h"
+#include "wcore_util.h"
+
+struct wcore_config_attrs;
+struct wcore_platform;
+struct wgl_window;
+
+struct wgl_config {
+ struct wcore_config wcore;
+ PIXELFORMATDESCRIPTOR pfd;
+ int pixel_format;
+
+ // XXX: Currently we manage only one window per config.
+ struct wgl_window *window;
+};
+
+static inline struct wgl_config*
+wgl_config(struct wcore_config *wcore)
+{
+ return (struct wgl_config *)wcore;
+}
+
+struct wcore_config*
+wgl_config_choose(struct wcore_platform *wc_plat,
+ struct wcore_display *wc_dpy,
+ const struct wcore_config_attrs *attrs);
+
+bool
+wgl_config_destroy(struct wcore_config *wc_self);
diff --git a/src/waffle/wgl/wgl_context.c b/src/waffle/wgl/wgl_context.c
new file mode 100644
index 0000000..dd45f81
--- /dev/null
+++ b/src/waffle/wgl/wgl_context.c
@@ -0,0 +1,212 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <assert.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include "wcore_error.h"
+
+#include "wgl_config.h"
+#include "wgl_context.h"
+#include "wgl_display.h"
+#include "wgl_error.h"
+#include "wgl_window.h"
+
+bool
+wgl_context_destroy(struct wcore_context *wc_self)
+{
+ struct wgl_context *self = wgl_context(wc_self);
+ bool ok = true;
+
+ if (!self)
+ return true;
+
+ if (self->hglrc)
+ ok &= wglDeleteContext(self->hglrc);
+
+ ok &= wcore_context_teardown(wc_self);
+ free(self);
+ return ok;
+}
+
+
+/// @brief Fill @a attrib_list, which will be given to wglCreateContextAttribsARB().
+///
+/// This does not validate the `config->context_*` attributes. That validation
+/// occurred during waffle_config_choose().
+static bool
+wgl_context_fill_attrib_list(struct wgl_config *config,
+ int attrib_list[])
+{
+ struct wcore_config_attrs *attrs = &config->wcore.attrs;
+ int i = 0;
+ int context_flags = 0;
+
+ // XXX: Check if the following workaround is relevant under Windows.
+
+ // As a workaround for NVidia, do not specify
+ // WGL_CONTEXT_MAJOR_VERSION_ARB and WGL_CONTEXT_MINOR_VERSION_ARB in the
+ // call to wglCreateContextAttribsARB if the user requested an OpenGL
+ // context of unspecified version or if the user explicitly requested an
+ // OpenGL 1.0 context.
+ //
+ // Calling wglCreateContextAttribARB with MAJOR=1 and MINOR=0, according
+ // to the spec, is equivalent to calling it with MAJOR and MINOR
+ // unspecified. From the WGL_ARB_create_context spec:
+ //
+ // If an attribute is not specified in <attrib_list>,
+ // then the default value specified below is used instead.
+ //
+ // The default values for WGL_CONTEXT_MAJOR_VERSION_ARB and
+ // WGL_CONTEXT_MINOR_VERSION_ARB are 1 and 0 respectively. In this
+ // case, implementations will typically return the most recent version
+ // of OpenGL they support which is backwards compatible with OpenGL 1.0
+ // (e.g. 3.0, 3.1 + GL_ARB_compatibility, or 3.2 compatibility profile)
+ //
+ // However, NVidia's libGL, circa 2012-12-19, is not compliant. Calling
+ // wglCreateContextAttribsARB with MAJOR=1 and MINOR=0 returns an OpenGL
+ // 2.1 context. Calling it with MAJOR and MINOR unspecified returns
+ // a context of the latest supported OpenGL version.
+ if (!(wcore_config_attrs_version_eq(attrs, 10) &&
+ attrs->context_api == WAFFLE_CONTEXT_OPENGL))
+ {
+ attrib_list[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ attrib_list[i++] = attrs->context_major_version;
+
+ attrib_list[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+ attrib_list[i++] = attrs->context_minor_version;
+ }
+
+ switch (attrs->context_api) {
+ case WAFFLE_CONTEXT_OPENGL:
+ if (wcore_config_attrs_version_ge(attrs, 32)) {
+ switch (attrs->context_profile) {
+ case WAFFLE_CONTEXT_CORE_PROFILE:
+ attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+ attrib_list[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+ break;
+ case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
+ attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+ attrib_list[i++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+
+ if (attrs->context_forward_compatible) {
+ context_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+ }
+
+ break;
+ case WAFFLE_CONTEXT_OPENGL_ES1:
+ case WAFFLE_CONTEXT_OPENGL_ES2:
+ case WAFFLE_CONTEXT_OPENGL_ES3:
+ attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+ attrib_list[i++] = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+ break;
+ }
+
+ if (attrs->context_debug) {
+ context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+ }
+
+ if (context_flags != 0) {
+ attrib_list[i++] = WGL_CONTEXT_FLAGS_ARB;
+ attrib_list[i++] = context_flags;
+ }
+
+ attrib_list[i++] = 0;
+ return true;
+}
+
+static HGLRC
+wgl_context_create_native(struct wgl_config *config,
+ struct wgl_context *share_ctx)
+{
+ struct wgl_display *dpy = wgl_display(config->wcore.display);
+ HGLRC real_share_ctx = share_ctx ? share_ctx->hglrc : NULL;
+ HGLRC hglrc;
+
+ if (dpy->ARB_create_context) {
+ bool ok;
+
+ // Choose a large size to prevent accidental overflow.
+ int attrib_list[64];
+
+ ok = wgl_context_fill_attrib_list(config, attrib_list);
+ if (!ok)
+ return NULL;
+
+ hglrc = dpy->wglCreateContextAttribsARB(config->window->hDC,
+ real_share_ctx,
+ attrib_list);
+ if (!hglrc) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglCreateContextAttribsARB failed");
+ return NULL;
+ }
+ }
+ else {
+ hglrc = wglCreateContext(config->window->hDC);
+ if (!hglrc) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN, "wglCreateContext failed");
+ return NULL;
+ }
+ }
+
+ return hglrc;
+}
+
+struct wcore_context*
+wgl_context_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ struct wcore_context *wc_share_ctx)
+{
+ struct wgl_config *config = wgl_config(wc_config);
+ struct wgl_context *share_ctx = wgl_context(wc_share_ctx);
+ struct wgl_context *self;
+ int error;
+
+ self = wcore_calloc(sizeof(*self));
+ if (!self)
+ return NULL;
+
+ error = !wcore_context_init(&self->wcore, wc_config);
+ if (error)
+ goto fail;
+
+ self->hglrc = wgl_context_create_native(config, share_ctx);
+ if (!self->hglrc)
+ goto fail;
+
+ return &self->wcore;
+
+fail:
+ wgl_context_destroy(&self->wcore);
+ return NULL;
+}
diff --git a/src/waffle/wgl/wgl_context.h b/src/waffle/wgl/wgl_context.h
new file mode 100644
index 0000000..c55ad58
--- /dev/null
+++ b/src/waffle/wgl/wgl_context.h
@@ -0,0 +1,53 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "wcore_context.h"
+#include "wcore_util.h"
+
+struct wcore_config;
+struct wcore_platform;
+
+struct wgl_context {
+ struct wcore_context wcore;
+ HGLRC hglrc;
+};
+
+static inline struct wgl_context*
+wgl_context(struct wcore_context *wcore)
+{
+ return (struct wgl_context *)wcore;
+}
+
+struct wcore_context*
+wgl_context_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ struct wcore_context *wc_share_ctx);
+
+bool
+wgl_context_destroy(struct wcore_context *wc_self);
diff --git a/src/waffle/wgl/wgl_display.c b/src/waffle/wgl/wgl_display.c
new file mode 100644
index 0000000..9b3b38e
--- /dev/null
+++ b/src/waffle/wgl/wgl_display.c
@@ -0,0 +1,275 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <stdlib.h>
+#include <windows.h>
+#include "c99_compat.h"
+
+#include "wcore_error.h"
+
+#include "wgl_display.h"
+#include "wgl_dl.h"
+#include "wgl_platform.h"
+
+bool
+wgl_display_destroy(struct wcore_display *wc_self)
+{
+ struct wgl_display *self = wgl_display(wc_self);
+ bool ok = true;
+
+ if (!self)
+ return true;
+
+ if (self->hWnd) {
+ if (self->hglrc) {
+ ok &= wglDeleteContext(self->hglrc);
+ }
+
+ if (self->hDC)
+ ok &= ReleaseDC(self->hWnd, self->hDC);
+
+ ok &= DestroyWindow(self->hWnd);
+ }
+
+ ok &= wcore_display_teardown(wc_self);
+ free(self);
+ return ok;
+}
+
+static bool
+wgl_display_create_window(struct wgl_platform *plat, struct wgl_display *dpy)
+{
+ dpy->hWnd = CreateWindow(plat->class_name, NULL,
+ WS_POPUPWINDOW|WS_DISABLED,
+ 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (!dpy->hWnd)
+ return false;
+
+ dpy->hDC = GetDC(dpy->hWnd);
+ if (!dpy->hDC)
+ return false;
+
+ return true;
+}
+
+static bool
+wgl_display_choose_config(struct wgl_display *dpy)
+{
+ // XXX: Is there a move common/appropriate pixelformat ?
+ PIXELFORMATDESCRIPTOR pfd = {0};
+ bool ok;
+
+ pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pfd.nVersion = 1;
+
+ pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
+
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+ pfd.cColorBits = 32;
+ pfd.cDepthBits = 16;
+
+ dpy->pixel_format = ChoosePixelFormat(dpy->hDC, &pfd);
+ if (!dpy->pixel_format)
+ return false;
+
+ ok = SetPixelFormat(dpy->hDC, dpy->pixel_format, &pfd);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+static bool
+wgl_display_hardware_render(struct wgl_display *dpy)
+{
+#ifndef GL_RENDERER
+#define GL_RENDERER 0x1F01
+#endif
+ typedef unsigned int GLenum;
+ typedef unsigned char GLubyte;
+ typedef const GLubyte * (__stdcall *PFNGLGETSTRINGPROC)(GLenum name);
+
+ PFNGLGETSTRINGPROC glGetString_func;
+ const GLubyte *gl_renderer;
+
+ glGetString_func = wgl_dl_sym(dpy->wcore.platform, WAFFLE_DL_OPENGL, "glGetString");
+ if (!glGetString_func)
+ return false;
+
+ gl_renderer = glGetString_func(GL_RENDERER);
+
+ // Bail out if we cannot retrieve the renderer string or if we're using GDI
+ if (!gl_renderer || strcasecmp((const char *)gl_renderer, "GDI Generic") == 0)
+ return false;
+
+ return true;
+}
+
+static bool
+wgl_display_set_extensions(struct wgl_display *dpy)
+{
+ typedef const char * (__stdcall *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
+ PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB_func;
+ const char *extensions;
+
+ wglGetExtensionsStringARB_func = (void *)wglGetProcAddress("wglGetExtensionsStringARB");
+ if (!wglGetExtensionsStringARB_func) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglGetProcAddress(\"wglGetExtensionsStringARB\") failed");
+ return false;
+ }
+
+ extensions = wglGetExtensionsStringARB_func(dpy->hDC);
+
+ if (!extensions) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglGetExtensionsStringARB failed");
+ return false;
+ }
+
+ dpy->ARB_create_context = waffle_is_extension_in_string(extensions, "WGL_ARB_create_context");
+ dpy->ARB_create_context_profile = waffle_is_extension_in_string(extensions, "WGL_ARB_create_context_profile");
+ dpy->EXT_create_context_es_profile = waffle_is_extension_in_string(extensions, "WGL_EXT_create_context_es_profile");
+
+ // The WGL_EXT_create_context_es2_profile spec, version 5 2012/04/06,
+ // states that WGL_EXT_create_context_es_profile is an alias of
+ // WGL_EXT_create_context_es2_profile and requires that both names must be
+ // exported together for backwards compatibility with clients that expect
+ // the es2_profile name.
+ if (dpy->EXT_create_context_es_profile) {
+ dpy->EXT_create_context_es2_profile = true;
+ }
+ else {
+ // Assume that WGL does not implement version 3 of the extension, in
+ // which case the ES contexts WGL is capable of creating is ES2.
+ dpy->EXT_create_context_es2_profile = waffle_is_extension_in_string(extensions, "WGL_EXT_create_context_es2_profile");
+ }
+
+ dpy->ARB_pixel_format = waffle_is_extension_in_string(extensions, "WGL_ARB_pixel_format");
+
+ return true;
+}
+
+static bool
+wgl_display_set_func_ptrs(struct wgl_display *dpy)
+{
+ if (dpy->ARB_create_context) {
+ dpy->wglCreateContextAttribsARB = (void *)wglGetProcAddress("wglCreateContextAttribsARB");
+ if (!dpy->wglCreateContextAttribsARB) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglGetProcAddress(\"wglCreateContextAttribsARB\") failed");
+ return false;
+ }
+ }
+
+ if (dpy->ARB_pixel_format) {
+ dpy->wglChoosePixelFormatARB = (void *)wglGetProcAddress("wglChoosePixelFormatARB");
+ if (!dpy->wglChoosePixelFormatARB) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "wglGetProcAddress(\"wglChoosePixelFormatARB\") failed");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+struct wcore_display*
+wgl_display_connect(struct wcore_platform *wc_plat,
+ const char *name)
+{
+ struct wgl_display *self;
+ bool ok;
+
+ self = wcore_calloc(sizeof(*self));
+ if (!self)
+ return NULL;
+
+ ok = wcore_display_init(&self->wcore, wc_plat);
+ if (!ok)
+ goto error;
+
+ ok = wgl_display_create_window(wgl_platform(wc_plat), self);
+ if (!ok)
+ goto error;
+
+ ok = wgl_display_choose_config(self);
+ if (!ok)
+ goto error;
+
+ self->hglrc = wglCreateContext(self->hDC);
+ if (!self->hglrc)
+ goto error;
+
+ ok = wglMakeCurrent(self->hDC, self->hglrc);
+ if (!ok)
+ goto error;
+
+ ok = wgl_display_hardware_render(self);
+ if (!ok)
+ goto error;
+
+ ok = wgl_display_set_extensions(self);
+ if (!ok)
+ goto error;
+
+ ok = wgl_display_set_func_ptrs(self);
+ if (!ok)
+ goto error;
+
+ ok = wglMakeCurrent(NULL, NULL);
+ if (!ok)
+ goto error;
+
+ return &self->wcore;
+
+error:
+ wgl_display_destroy(&self->wcore);
+ return NULL;
+}
+
+bool
+wgl_display_supports_context_api(struct wcore_display *wc_self,
+ int32_t context_api)
+{
+ struct wgl_display *self = wgl_display(wc_self);
+
+ switch (context_api) {
+ case WAFFLE_CONTEXT_OPENGL:
+ return true;
+ case WAFFLE_CONTEXT_OPENGL_ES1:
+ return self->EXT_create_context_es_profile;
+ case WAFFLE_CONTEXT_OPENGL_ES2:
+ return self->EXT_create_context_es2_profile;
+ case WAFFLE_CONTEXT_OPENGL_ES3:
+ return self->EXT_create_context_es_profile;
+ default:
+ wcore_error_internal("waffle_context_api has bad value %#x",
+ context_api);
+ return false;
+ }
+}
diff --git a/src/waffle/wgl/wgl_display.h b/src/waffle/wgl/wgl_display.h
new file mode 100644
index 0000000..d0d94fe
--- /dev/null
+++ b/src/waffle/wgl/wgl_display.h
@@ -0,0 +1,81 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "wcore_display.h"
+#include "wcore_util.h"
+
+struct wcore_platform;
+
+// XXX: Move the typedefs ?
+typedef HGLRC (__stdcall *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC,
+ HGLRC hShareContext,
+ const int *attribList);
+
+typedef BOOL (__stdcall *PFNWGLCHOOSEPIXELFORMATARBPROC )(HDC hdc,
+ const int * piAttribIList,
+ const float * pfAttribFList,
+ unsigned int nMaxFormats,
+ int * piFormats,
+ unsigned int * nNumFormats);
+
+struct wgl_display {
+ struct wcore_display wcore;
+
+ HWND hWnd;
+ HDC hDC;
+ int pixel_format;
+ HGLRC hglrc;
+
+ bool ARB_create_context;
+ bool ARB_create_context_profile;
+ bool EXT_create_context_es_profile;
+ bool EXT_create_context_es2_profile;
+ bool ARB_pixel_format;
+
+ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+ PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+};
+
+static inline struct wgl_display*
+wgl_display(struct wcore_display *wcore)
+{
+ return (struct wgl_display*)wcore;
+}
+
+struct wcore_display*
+wgl_display_connect(struct wcore_platform *wc_plat,
+ const char *name);
+
+bool
+wgl_display_destroy(struct wcore_display *wc_self);
+
+bool
+wgl_display_supports_context_api(struct wcore_display *wc_self,
+ int32_t context_api);
diff --git a/src/waffle/wgl/wgl_dl.c b/src/waffle/wgl/wgl_dl.c
new file mode 100644
index 0000000..9d05cb9
--- /dev/null
+++ b/src/waffle/wgl/wgl_dl.c
@@ -0,0 +1,143 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <assert.h>
+#include <windows.h>
+
+#include "wcore_error.h"
+
+#include "wgl_dl.h"
+#include "wgl_platform.h"
+
+static const char *wgl_gl_path = "OPENGL32";
+
+static bool
+wgl_dl_check_enum(int32_t waffle_dl)
+{
+ switch (waffle_dl) {
+ case WAFFLE_DL_OPENGL:
+ case WAFFLE_DL_OPENGL_ES1:
+ case WAFFLE_DL_OPENGL_ES2:
+ case WAFFLE_DL_OPENGL_ES3:
+ // OPENGL32.DLL provides GL and GLES* symbols.
+ return true;
+ default:
+ assert(false);
+ return false;
+ }
+}
+
+static bool
+wgl_dl_open(struct wgl_platform *plat)
+{
+ plat->dl_gl = LoadLibraryA(wgl_gl_path);
+
+ if (plat->dl_gl)
+ return true;
+
+ int error = GetLastError();
+
+ if (error) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "LoadLibraryA(\"%s\") failed: %d",
+ wgl_gl_path, error);
+ }
+
+ return false;
+}
+
+bool
+wgl_dl_can_open(struct wcore_platform *wc_plat,
+ int32_t waffle_dl)
+{
+ struct wgl_platform *plat = wgl_platform(wc_plat);
+
+ if (!wgl_dl_check_enum(waffle_dl))
+ return false;
+
+ if (plat->dl_gl)
+ return true;
+
+ WCORE_ERROR_DISABLED({
+ wgl_dl_open(plat);
+ });
+
+ return plat->dl_gl != NULL;
+}
+
+void*
+wgl_dl_sym(struct wcore_platform *wc_plat,
+ int32_t waffle_dl,
+ const char *name)
+{
+ struct wgl_platform *plat = wgl_platform(wc_plat);
+
+ if (!wgl_dl_check_enum(waffle_dl))
+ return NULL;
+
+ if (!plat->dl_gl)
+ wgl_dl_open(plat);
+
+ if (!plat->dl_gl)
+ return NULL;
+
+ void *sym = GetProcAddress(plat->dl_gl, name);
+
+ if (sym)
+ return sym;
+
+ int error = GetLastError();
+
+ if (error) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "GetProcAddress(libname=\"%s\", symbol=\"%s\") failed: %d",
+ wgl_gl_path, name, error);
+ }
+
+ return NULL;
+}
+
+bool
+wgl_dl_close(struct wcore_platform *wc_plat)
+{
+ struct wgl_platform *plat = wgl_platform(wc_plat);
+
+ if (!plat->dl_gl)
+ return true;
+
+ if (FreeLibrary(plat->dl_gl))
+ return true;
+
+ int error = GetLastError();
+
+ if (error) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "FreeLibrary(libname=\"%s\") failed: %d",
+ wgl_gl_path, error);
+ }
+
+ return false;
+}
diff --git a/src/waffle/wgl/wgl_dl.h b/src/waffle/wgl/wgl_dl.h
new file mode 100644
index 0000000..6ccd170
--- /dev/null
+++ b/src/waffle/wgl/wgl_dl.h
@@ -0,0 +1,43 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct wcore_platform;
+
+bool
+wgl_dl_can_open(struct wcore_platform *wc_plat,
+ int32_t waffle_dl);
+
+void*
+wgl_dl_sym(struct wcore_platform *wc_plat,
+ int32_t waffle_dl,
+ const char *name);
+
+bool
+wgl_dl_close(struct wcore_platform *wc_plat);
diff --git a/src/waffle/wgl/wgl_error.c b/src/waffle/wgl/wgl_error.c
new file mode 100644
index 0000000..679ff43
--- /dev/null
+++ b/src/waffle/wgl/wgl_error.c
@@ -0,0 +1,48 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "wcore_error.h"
+
+#include "wgl_error.h"
+
+const char*
+wgl_error_to_string(int error_code)
+{
+ return NULL;
+}
+
+void
+wgl_error_failed_func(const char *func_name, int error_code)
+{
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "%s failed with %s: %s",
+ func_name,
+ wgl_error_to_string(error_code),
+ NULL);
+}
diff --git a/src/waffle/wgl/wgl_error.h b/src/waffle/wgl/wgl_error.h
new file mode 100644
index 0000000..aca0769
--- /dev/null
+++ b/src/waffle/wgl/wgl_error.h
@@ -0,0 +1,32 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+const char*
+wgl_error_to_string(int error_code);
+
+void
+wgl_error_failed_func(const char *func_name, int error_code);
diff --git a/src/waffle/wgl/wgl_platform.c b/src/waffle/wgl/wgl_platform.c
new file mode 100644
index 0000000..f4649b4
--- /dev/null
+++ b/src/waffle/wgl/wgl_platform.c
@@ -0,0 +1,173 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <stdlib.h>
+#include <windows.h>
+
+#include "wcore_error.h"
+
+#include "wgl_config.h"
+#include "wgl_context.h"
+#include "wgl_display.h"
+#include "wgl_dl.h"
+#include "wgl_platform.h"
+#include "wgl_window.h"
+
+static const struct wcore_platform_vtbl wgl_platform_vtbl;
+
+const char* wfl_class_name = "waffle";
+
+static bool
+wgl_platform_destroy(struct wcore_platform *wc_self)
+{
+ struct wgl_platform *self = wgl_platform(wc_self);
+ bool ok = true;
+
+ if (!self)
+ return true;
+
+ if (self->dl_gl)
+ ok &= wgl_dl_close(wc_self);
+
+ if (self->class_name)
+ ok &= UnregisterClass(self->class_name, GetModuleHandle(NULL));
+
+ ok &= wcore_platform_teardown(wc_self);
+ free(self);
+ return ok;
+}
+
+static bool
+wgl_platform_register_class(const char* class_name)
+{
+ WNDCLASS wc;
+ bool ok;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+ // XXX: Use a non-default window_proc ?
+ wc.lpfnWndProc = DefWindowProc;
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);;
+ wc.lpszClassName = class_name;
+
+ ok = !!RegisterClass(&wc);
+
+ if (!ok) {
+ int error = GetLastError();
+
+ if (error) {
+ wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+ "RegisterClass() failed: %d",
+ error);
+ }
+ }
+
+ return ok;
+}
+
+struct wcore_platform*
+wgl_platform_create(void)
+{
+ struct wgl_platform *self;
+ bool ok;
+
+ self = wcore_calloc(sizeof(*self));
+ if (!self)
+ return NULL;
+
+ ok = wcore_platform_init(&self->wcore);
+ if (!ok)
+ goto error;
+
+ ok = wgl_platform_register_class(wfl_class_name);
+ if (!ok)
+ goto error;
+ self->class_name = wfl_class_name;
+
+ self->wcore.vtbl = &wgl_platform_vtbl;
+ return &self->wcore;
+
+error:
+ wgl_platform_destroy(&self->wcore);
+ return NULL;
+}
+
+static bool
+wgl_make_current(struct wcore_platform *wc_self,
+ struct wcore_display *wc_dpy,
+ struct wcore_window *wc_window,
+ struct wcore_context *wc_ctx)
+{
+ HDC hDC = wc_window ? wgl_window(wc_window)->hDC : NULL;
+ HGLRC hglrc = wc_ctx ? wgl_context(wc_ctx)->hglrc : NULL;
+
+ return wglMakeCurrent(hDC, hglrc);
+}
+
+static void*
+wgl_get_proc_address(struct wcore_platform *wc_self, const char *name)
+{
+ return wglGetProcAddress(name);
+}
+
+static const struct wcore_platform_vtbl wgl_platform_vtbl = {
+ .destroy = wgl_platform_destroy,
+
+ .make_current = wgl_make_current,
+ .get_proc_address = wgl_get_proc_address,
+ .dl_can_open = wgl_dl_can_open,
+ .dl_sym = wgl_dl_sym,
+
+ .display = {
+ .connect = wgl_display_connect,
+ .destroy = wgl_display_destroy,
+ .supports_context_api = wgl_display_supports_context_api,
+ .get_native = NULL,
+ },
+
+ .config = {
+ .choose = wgl_config_choose,
+ .destroy = wgl_config_destroy,
+ .get_native = NULL,
+ },
+
+ .context = {
+ .create = wgl_context_create,
+ .destroy = wgl_context_destroy,
+ .get_native = NULL,
+ },
+
+ .window = {
+ .create = wgl_window_create,
+ .destroy = wgl_window_destroy,
+ .show = wgl_window_show,
+ .resize = wgl_window_resize,
+ .swap_buffers = wgl_window_swap_buffers,
+ .get_native = NULL,
+ },
+};
diff --git a/src/waffle/wgl/wgl_platform.h b/src/waffle/wgl/wgl_platform.h
new file mode 100644
index 0000000..a25d2f4
--- /dev/null
+++ b/src/waffle/wgl/wgl_platform.h
@@ -0,0 +1,53 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include "wcore_platform.h"
+#include "wcore_util.h"
+
+struct wgl_platform {
+ struct wcore_platform wcore;
+
+ /// @brief The full system version number - (major << 8) | minor.
+ ///
+ /// For example, 0x0501 indicates Windows XP.
+ int32_t system_version_full;
+
+ /// @brief The OpenGL library obtained with LoadLibraryA().
+ void *dl_gl;
+
+ /// @brief The class name of the waffle windows.
+ const char *class_name;
+};
+
+static inline struct wgl_platform*
+wgl_platform(struct wcore_platform *wcore)
+{
+ return (struct wgl_platform*)wcore;
+}
+
+struct wcore_platform*
+wgl_platform_create(void);
diff --git a/src/waffle/wgl/wgl_window.c b/src/waffle/wgl/wgl_window.c
new file mode 100644
index 0000000..7c3932f
--- /dev/null
+++ b/src/waffle/wgl/wgl_window.c
@@ -0,0 +1,212 @@
+// Copyright 2014 Emil Velikov
+//
+// 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 <windows.h>
+
+#include "wcore_error.h"
+
+#include "wgl_config.h"
+#include "wgl_platform.h"
+#include "wgl_window.h"
+
+bool
+wgl_window_destroy(struct wcore_window *wc_self)
+{
+ struct wgl_window *self = wgl_window(wc_self);
+
+ assert(self);
+ assert(self->hWnd);
+
+ self->created = false;
+ ShowWindow(self->hWnd, SW_HIDE);
+ return true;
+}
+
+bool
+wgl_window_priv_destroy(struct wcore_window *wc_self)
+{
+ struct wgl_window *self = wgl_window(wc_self);
+ bool ok = true;
+
+ if (!self)
+ return true;
+
+ if (self->hWnd) {
+ if (self->hDC) {
+ ok &= ReleaseDC(self->hWnd, self->hDC);
+ }
+ ok &= DestroyWindow(self->hWnd);
+ }
+
+ ok &= wcore_window_teardown(wc_self);
+ free(self);
+ return ok;
+}
+
+struct wcore_window*
+wgl_window_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ int width,
+ int height)
+{
+ struct wgl_config *config = wgl_config(wc_config);
+ bool ok;
+
+ assert(config->window);
+
+ // Currently we do not allow multiple windows per config.
+ // Neither piglit nor the waffle examples do that yet, so just
+ // return NULL in case that ever changes.
+ assert(!config->window->created);
+ if (config->window->created)
+ return NULL;
+
+ config->window->created = true;
+
+ ok = wgl_window_resize(&config->window->wcore, width, height);
+ if (!ok)
+ return NULL;
+
+ return &config->window->wcore;
+}
+
+struct wcore_window*
+wgl_window_priv_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ int width,
+ int height)
+{
+ struct wgl_platform *plat = wgl_platform(wc_plat);
+ struct wgl_window *self;
+ bool ok;
+ RECT rect;
+
+ self = wcore_calloc(sizeof(*self));
+ if (!self)
+ return NULL;
+
+ ok = wcore_window_init(&self->wcore, wc_config);
+ if (!ok)
+ goto error;
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = rect.left + width;
+ rect.bottom = rect.top + height;
+
+ ok = AdjustWindowRect(&rect, WS_POPUPWINDOW, FALSE);
+ if (!ok)
+ goto error;
+
+ self->hWnd = CreateWindow(plat->class_name, NULL, WS_POPUPWINDOW,
+ 0, 0,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, NULL, NULL);
+ if (!self->hWnd)
+ goto error;
+
+#ifndef NDEBUG
+ // Verify the client area size matches the required size.
+
+ GetClientRect(self->hWnd, &rect);
+ assert(rect.left == 0);
+ assert(rect.top == 0);
+ assert(rect.right - rect.left == width);
+ assert(rect.bottom - rect.top == height);
+#endif
+
+ self->hDC = GetDC(self->hWnd);
+ if (!self->hDC)
+ goto error;
+
+ return &self->wcore;
+
+error:
+ wgl_window_priv_destroy(&self->wcore);
+ return NULL;
+}
+
+bool
+wgl_window_show(struct wcore_window *wc_self)
+{
+ struct wgl_window *self = wgl_window(wc_self);
+
+ assert(self);
+ assert(self->hWnd);
+
+ // If the window was previously hidden the function returns zero,
+ // and non-zero otherwise.
+ // XXX: Use SW_SHOW or SW_SHOWDEFAULT, SW_SHOWNORMAL ?
+ ShowWindow(self->hWnd, SW_SHOW);
+ return true;
+}
+
+bool
+wgl_window_resize(struct wcore_window *wc_self,
+ int32_t width, int32_t height)
+{
+ struct wgl_window *self = wgl_window(wc_self);
+ RECT rect;
+ bool ok;
+
+ assert(self);
+ assert(self->hWnd);
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = rect.left + width;
+ rect.bottom = rect.top + height;
+
+ ok = AdjustWindowRect(&rect, WS_POPUPWINDOW, FALSE);
+ if (!ok)
+ return false;
+
+ ok = SetWindowPos(self->hWnd, 0, 0, 0,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+
+#ifndef NDEBUG
+ // Verify the client area size matches the required size.
+
+ GetClientRect(self->hWnd, &rect);
+ assert(rect.left == 0);
+ assert(rect.top == 0);
+ assert(rect.right - rect.left == width);
+ assert(rect.bottom - rect.top == height);
+#endif
+ return ok;
+}
+
+bool
+wgl_window_swap_buffers(struct wcore_window *wc_self)
+{
+ struct wgl_window *self = wgl_window(wc_self);
+
+ assert(self);
+ assert(self->hDC);
+
+ return SwapBuffers(self->hDC);
+}
diff --git a/src/waffle/wgl/wgl_window.h b/src/waffle/wgl/wgl_window.h
new file mode 100644
index 0000000..a60205d
--- /dev/null
+++ b/src/waffle/wgl/wgl_window.h
@@ -0,0 +1,77 @@
+// Copyright 2014 Emil Velikov
+//
+// 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.
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "wcore_util.h"
+#include "wcore_window.h"
+
+struct wcore_platform;
+
+struct wgl_window {
+ struct wcore_window wcore;
+ HWND hWnd;
+ HDC hDC;
+ bool created;
+};
+
+static inline struct wgl_window*
+wgl_window(struct wcore_window *wcore)
+{
+ return (struct wgl_window*)wcore;
+}
+
+struct wcore_window*
+wgl_window_priv_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ int width,
+ int height);
+
+bool
+wgl_window_priv_destroy(struct wcore_window *wc_self);
+
+struct wcore_window*
+wgl_window_create(struct wcore_platform *wc_plat,
+ struct wcore_config *wc_config,
+ int width,
+ int height);
+
+bool
+wgl_window_destroy(struct wcore_window *wc_self);
+
+bool
+wgl_window_show(struct wcore_window *wc_self);
+
+bool
+wgl_window_resize(struct wcore_window *wc_self,
+ int32_t width, int32_t height);
+
+bool
+wgl_window_swap_buffers(struct wcore_window *wc_self);
+
+union waffle_native_window*
+wgl_window_get_native(struct wcore_window *wc_self);
diff --git a/src/waffle/xegl/xegl_platform.c b/src/waffle/xegl/xegl_platform.c
index 71bf23c..e36a41b 100644
--- a/src/waffle/xegl/xegl_platform.c
+++ b/src/waffle/xegl/xegl_platform.c
@@ -31,6 +31,7 @@
#include "wegl_config.h"
#include "wegl_context.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "linux_platform.h"
@@ -44,7 +45,7 @@ static const struct wcore_platform_vtbl xegl_platform_vtbl;
static bool
xegl_platform_destroy(struct wcore_platform *wc_self)
{
- struct xegl_platform *self = xegl_platform(wc_self);
+ struct xegl_platform *self = xegl_platform(wegl_platform(wc_self));
bool ok = true;
if (!self)
@@ -55,7 +56,7 @@ xegl_platform_destroy(struct wcore_platform *wc_self)
if (self->linux)
ok &= linux_platform_destroy(self->linux);
- ok &= wcore_platform_teardown(wc_self);
+ ok &= wegl_platform_teardown(&self->wegl);
free(self);
return ok;
}
@@ -70,7 +71,7 @@ xegl_platform_create(void)
if (self == NULL)
return NULL;
- ok = wcore_platform_init(&self->wcore);
+ ok = wegl_platform_init(&self->wegl);
if (!ok)
goto error;
@@ -80,11 +81,11 @@ xegl_platform_create(void)
setenv("EGL_PLATFORM", "x11", true);
- self->wcore.vtbl = &xegl_platform_vtbl;
- return &self->wcore;
+ self->wegl.wcore.vtbl = &xegl_platform_vtbl;
+ return &self->wegl.wcore;
error:
- xegl_platform_destroy(&self->wcore);
+ xegl_platform_destroy(&self->wegl.wcore);
return NULL;
}
@@ -92,8 +93,8 @@ static bool
xegl_dl_can_open(struct wcore_platform *wc_self,
int32_t waffle_dl)
{
- return linux_platform_dl_can_open(xegl_platform(wc_self)->linux,
- waffle_dl);
+ struct xegl_platform *self = xegl_platform(wegl_platform(wc_self));
+ return linux_platform_dl_can_open(self->linux, waffle_dl);
}
static void*
@@ -101,9 +102,8 @@ xegl_dl_sym(struct wcore_platform *wc_self,
int32_t waffle_dl,
const char *name)
{
- return linux_platform_dl_sym(xegl_platform(wc_self)->linux,
- waffle_dl,
- name);
+ struct xegl_platform *self = xegl_platform(wegl_platform(wc_self));
+ return linux_platform_dl_sym(self->linux, waffle_dl, name);
}
static union waffle_native_config*
diff --git a/src/waffle/xegl/xegl_platform.h b/src/waffle/xegl/xegl_platform.h
index 835f360..003343f 100644
--- a/src/waffle/xegl/xegl_platform.h
+++ b/src/waffle/xegl/xegl_platform.h
@@ -31,20 +31,20 @@
#include "waffle_x11_egl.h"
-#include "wcore_platform.h"
+#include "wegl_platform.h"
#include "wcore_util.h"
struct linux_platform;
struct xegl_platform {
- struct wcore_platform wcore;
+ struct wegl_platform wegl;
struct linux_platform *linux;
};
DEFINE_CONTAINER_CAST_FUNC(xegl_platform,
struct xegl_platform,
- struct wcore_platform,
- wcore)
+ struct wegl_platform,
+ wegl)
struct wcore_platform*
xegl_platform_create(void);
diff --git a/src/waffle/xegl/xegl_window.c b/src/waffle/xegl/xegl_window.c
index 5fcadda..ce638b4 100644
--- a/src/waffle/xegl/xegl_window.c
+++ b/src/waffle/xegl/xegl_window.c
@@ -31,6 +31,7 @@
#include "wcore_error.h"
#include "wegl_config.h"
+#include "wegl_platform.h"
#include "wegl_util.h"
#include "xegl_display.h"
@@ -60,6 +61,7 @@ xegl_window_create(struct wcore_platform *wc_plat,
struct xegl_window *self;
struct xegl_display *dpy = xegl_display(wc_config->display);
struct wegl_config *config = wegl_config(wc_config);
+ struct wegl_platform *plat = wegl_platform(wc_plat);
xcb_visualid_t visual;
bool ok = true;
@@ -67,12 +69,12 @@ xegl_window_create(struct wcore_platform *wc_plat,
if (self == NULL)
return NULL;
- ok = eglGetConfigAttrib(dpy->wegl.egl,
- config->egl,
- EGL_NATIVE_VISUAL_ID,
- (EGLint*) &visual);
+ ok = plat->eglGetConfigAttrib(dpy->wegl.egl,
+ config->egl,
+ EGL_NATIVE_VISUAL_ID,
+ (EGLint*) &visual);
if (!ok) {
- wegl_emit_error("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID)");
+ wegl_emit_error(plat, "eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID)");
goto error;
}
diff --git a/src/waffle_test/CMakeLists.txt b/src/waffle_test/CMakeLists.txt
index 40d2aba..8ed4ea2 100644
--- a/src/waffle_test/CMakeLists.txt
+++ b/src/waffle_test/CMakeLists.txt
@@ -3,7 +3,7 @@ include_directories(
"${CMAKE_SOURCE_DIR}/include/waffle_test/priv"
)
-add_library(waffle_test SHARED
+add_library(waffle_test STATIC
wt_main.c
wt_runner.c
wt_test.c
diff --git a/src/waffle_test/wt_main.c b/src/waffle_test/wt_main.c
index 205c83c..b3e6580 100644
--- a/src/waffle_test/wt_main.c
+++ b/src/waffle_test/wt_main.c
@@ -27,7 +27,11 @@
#include "priv/wt_runner.h"
int
+#ifdef _WIN32
+wt_main(int *argc, char **argv, void (__stdcall *test_suites[])(void))
+#else
wt_main(int *argc, char **argv, void (*test_suites[])(void))
+#endif // _WIN32
{
int num_fail;
diff --git a/src/waffle_test/wt_runner.c b/src/waffle_test/wt_runner.c
index 729c033..bd1e561 100644
--- a/src/waffle_test/wt_runner.c
+++ b/src/waffle_test/wt_runner.c
@@ -23,10 +23,6 @@
// 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.
-#ifdef __linux__
-# define _XOPEN_SOURCE 500 // for strdup()
-#endif
-
#include "wt_runner.h"
#include <stdbool.h>
diff --git a/tests/functional/CMakeLists.txt b/tests/functional/CMakeLists.txt
index febdf5f..f1388b2 100644
--- a/tests/functional/CMakeLists.txt
+++ b/tests/functional/CMakeLists.txt
@@ -1,8 +1,3 @@
-link_libraries(
- ${waffle_libname}
- waffle_test
- )
-
set(gl_basic_test_sources
gl_basic_test.c
)
@@ -13,11 +8,13 @@ if(waffle_on_mac)
)
endif()
-set_source_files_properties(
- ${gl_basic_test_sources}
- PROPERTIES
- COMPILE_FLAGS "-Wno-initializer-overrides"
-)
+if(NOT MSVC)
+ set_source_files_properties(
+ ${gl_basic_test_sources}
+ PROPERTIES
+ COMPILE_FLAGS "-Wno-initializer-overrides"
+ )
+endif()
# CMake will pass to the C compiler only C sources. CMake does not recognize the
# .m extension and ignores any such files in the source lists. To coerce CMake
@@ -32,9 +29,13 @@ add_executable(gl_basic_test
${gl_basic_test_sources}
)
+target_link_libraries(gl_basic_test
+ ${waffle_libname}
+ waffle_test
+ )
+
add_custom_target(gl_basic_test_run
- DEPENDS gl_basic_test
- COMMAND ${CMAKE_BINARY_DIR}/tests/functional/gl_basic_test
+ COMMAND gl_basic_test
)
add_dependencies(check-func gl_basic_test_run)
diff --git a/tests/functional/gl_basic_test.c b/tests/functional/gl_basic_test.c
index 035b221..0e932e3 100644
--- a/tests/functional/gl_basic_test.c
+++ b/tests/functional/gl_basic_test.c
@@ -37,10 +37,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if !defined(_WIN32)
#include <unistd.h>
+#else
+#include <windows.h>
+#endif
#include <sys/types.h>
+#if !defined(_WIN32)
#include <sys/wait.h>
+#endif
#include "waffle.h"
#include "waffle_test/waffle_test.h"
@@ -108,17 +114,25 @@ typedef double GLclampd; /* double precision float in [0,1] */
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
-static GLenum (*glGetError)(void);
-static void (*glGetIntegerv)(GLenum pname, GLint *params);
-static void (*glClearColor)(GLclampf red,
- GLclampf green,
- GLclampf blue,
- GLclampf alpha);
-static void (*glClear)(GLbitfield mask);
-static void (*glReadPixels)(GLint x, GLint y,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- GLvoid *pixels );
+#ifndef _WIN32
+#define APIENTRY
+#else
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+#endif
+
+static GLenum (APIENTRY *glGetError)(void);
+static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params);
+static void (APIENTRY *glClearColor)(GLclampf red,
+ GLclampf green,
+ GLclampf blue,
+ GLclampf alpha);
+static void (APIENTRY *glClear)(GLbitfield mask);
+static void (APIENTRY *glReadPixels)(GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels );
static void
testgroup_gl_basic_setup(void)
@@ -235,15 +249,6 @@ gl_basic_draw__(struct gl_basic_draw_args__ args)
config_attrib_list[i++] = alpha;
config_attrib_list[i++] = 0;
- // Check that we've set the EGL_PLATFORM environment variable for Mesa.
- //
- // If Mesa's libEGL is built with support for multiple platforms, then the
- // environment variable EGL_PLATFORM must be set before the first EGL
- // call. Otherwise, libEGL may initialize itself with the incorrect
- // platform. In my experiments, first calling eglGetProcAddress will
- // produce a segfault in eglInitialize.
- waffle_get_proc_address("glClear");
-
// Create objects.
ASSERT_TRUE(dpy = waffle_display_connect(NULL));
@@ -337,366 +342,129 @@ gl_basic_draw__(struct gl_basic_draw_args__ args)
ASSERT_TRUE(waffle_display_disconnect(dpy));
}
-#ifdef WAFFLE_HAS_CGL
-TEST(gl_basic, cgl_init)
-{
- gl_basic_init(WAFFLE_PLATFORM_CGL);
-}
-
-TEST(gl_basic, cgl_gles1_unsupported)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gles2_unsupported)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
+//
+// List of tests common to all platforms.
+//
-TEST(gl_basic, cgl_gl_rgb)
+TEST(gl_basic, all_gl_rgb)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL);
}
-TEST(gl_basic, cgl_gl_rgba)
+TEST(gl_basic, all_gl_rgba)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.alpha=true);
}
-TEST(gl_basic, cgl_gl_debug_is_unsupported)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .debug=true,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
-
-TEST(gl_basic, cgl_gl10)
+TEST(gl_basic, all_gl10)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=10);
}
-TEST(gl_basic, cgl_gl11)
+TEST(gl_basic, all_gl11)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=11);
}
-TEST(gl_basic, cgl_gl12)
+TEST(gl_basic, all_gl12)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=12);
}
-TEST(gl_basic, cgl_gl13)
+TEST(gl_basic, all_gl13)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=13);
}
-TEST(gl_basic, cgl_gl14)
+TEST(gl_basic, all_gl14)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=14);
}
-TEST(gl_basic, cgl_gl15)
+TEST(gl_basic, all_gl15)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=15);
}
-TEST(gl_basic, cgl_gl20)
+TEST(gl_basic, all_gl20)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=20);
}
-TEST(gl_basic, cgl_gl21)
+TEST(gl_basic, all_gl21)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=21);
}
-TEST(gl_basic, cgl_gl30)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=30,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl31)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=31);
-}
-
-TEST(gl_basic, cgl_gl32_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, cgl_gl33_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=33,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl40_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=40,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl41_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=41,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl42_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=42,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl43_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=43,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl32_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl33_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=33,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl40_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=40,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl41_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=41,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl42_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=42,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-TEST(gl_basic, cgl_gl43_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=43,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
- .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
-}
-
-static void
-testsuite_cgl(void)
-{
- TEST_RUN(gl_basic, cgl_init);
-
- TEST_RUN(gl_basic, cgl_gles1_unsupported);
- TEST_RUN(gl_basic, cgl_gles2_unsupported);
-
- TEST_RUN(gl_basic, cgl_gl_rgb);
- TEST_RUN(gl_basic, cgl_gl_rgba);
-
- TEST_RUN(gl_basic, cgl_gl_debug_is_unsupported);
- TEST_RUN(gl_basic, cgl_gl_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, cgl_gl10);
- TEST_RUN(gl_basic, cgl_gl11);
- TEST_RUN(gl_basic, cgl_gl12);
- TEST_RUN(gl_basic, cgl_gl13);
- TEST_RUN(gl_basic, cgl_gl14);
- TEST_RUN(gl_basic, cgl_gl15);
- TEST_RUN(gl_basic, cgl_gl20);
- TEST_RUN(gl_basic, cgl_gl21);
- TEST_RUN(gl_basic, cgl_gl30);
- TEST_RUN(gl_basic, cgl_gl31);
-
- TEST_RUN(gl_basic, cgl_gl32_core);
- TEST_RUN(gl_basic, cgl_gl33_core);
- TEST_RUN(gl_basic, cgl_gl40_core);
- TEST_RUN(gl_basic, cgl_gl41_core);
- TEST_RUN(gl_basic, cgl_gl42_core);
- TEST_RUN(gl_basic, cgl_gl43_core);
-
- TEST_RUN(gl_basic, cgl_gl32_compat);
- TEST_RUN(gl_basic, cgl_gl33_compat);
- TEST_RUN(gl_basic, cgl_gl40_compat);
- TEST_RUN(gl_basic, cgl_gl41_compat);
- TEST_RUN(gl_basic, cgl_gl42_compat);
- TEST_RUN(gl_basic, cgl_gl43_compat);
-}
-#endif // WAFFLE_HAS_CGL
-
-#ifdef WAFFLE_HAS_GLX
-TEST(gl_basic, glx_init)
-{
- gl_basic_init(WAFFLE_PLATFORM_GLX);
-}
-
-TEST(gl_basic, glx_gl_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL);
-}
-
-TEST(gl_basic, glx_gl_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .alpha=true);
-}
-
-TEST(gl_basic, glx_gl_debug)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .debug=true);
-}
-
-TEST(gl_basic, glx_gl_fwdcompat_bad_attribute)
+TEST(gl_basic, all_gl21_fwdcompat_bad_attribute)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
+ .version=21,
.forward_compatible=true,
.expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
-TEST(gl_basic, glx_gl10)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=10);
-}
-
-TEST(gl_basic, glx_gl11)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=11);
-}
-
-TEST(gl_basic, glx_gl12)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=12);
-}
-TEST(gl_basic, glx_gl13)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=13);
-}
-
-TEST(gl_basic, glx_gl14)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=14);
-}
-
-TEST(gl_basic, glx_gl15)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=15);
-}
-
-TEST(gl_basic, glx_gl20)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=20);
-}
-
-TEST(gl_basic, glx_gl21)
+//
+// List of linux (glx, wayland and x11_egl) and windows (wgl) specific tests.
+//
+#if defined(WAFFLE_HAS_GLX) || defined(WAFFLE_HAS_WAYLAND) || defined(WAFFLE_HAS_X11_EGL) || defined(WAFFLE_HAS_WGL)
+TEST(gl_basic, all_but_cgl_gl_debug)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21);
+ .debug=true);
}
-TEST(gl_basic, glx_gl21_fwdcompat_bad_attribute)
+TEST(gl_basic, all_but_cgl_gl_fwdcompat_bad_attribute)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21,
.forward_compatible=true,
.expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
-TEST(gl_basic, glx_gl30)
+TEST(gl_basic, all_but_cgl_gl30)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=30);
}
-TEST(gl_basic, glx_gl30_fwdcompat)
+TEST(gl_basic, all_but_cgl_gl30_fwdcompat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=30,
.forward_compatible=true);
}
-TEST(gl_basic, glx_gl31)
+TEST(gl_basic, all_but_cgl_gl31)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=31);
}
-TEST(gl_basic, glx_gl31_fwdcompat)
+TEST(gl_basic, all_but_cgl_gl31_fwdcompat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=31,
.forward_compatible=true);
}
-TEST(gl_basic, glx_gl32_core)
+TEST(gl_basic, all_but_cgl_gl32_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=32,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl32_core_fwdcompat)
+TEST(gl_basic, all_but_cgl_gl32_core_fwdcompat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=32,
@@ -704,505 +472,417 @@ TEST(gl_basic, glx_gl32_core_fwdcompat)
.forward_compatible=true);
}
-TEST(gl_basic, glx_gl33_core)
+TEST(gl_basic, all_but_cgl_gl33_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=33,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl40_core)
+TEST(gl_basic, all_but_cgl_gl40_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=40,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl41_core)
+TEST(gl_basic, all_but_cgl_gl41_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=41,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl42_core)
+TEST(gl_basic, all_but_cgl_gl42_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=42,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl43_core)
+TEST(gl_basic, all_but_cgl_gl43_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=43,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, glx_gl32_compat)
+TEST(gl_basic, all_but_cgl_gl32_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=32,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gl33_compat)
+TEST(gl_basic, all_but_cgl_gl33_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=33,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gl40_compat)
+TEST(gl_basic, all_but_cgl_gl40_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=40,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gl41_compat)
+TEST(gl_basic, all_but_cgl_gl41_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=41,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gl42_compat)
+TEST(gl_basic, all_but_cgl_gl42_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=42,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gl43_compat)
+TEST(gl_basic, all_but_cgl_gl43_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=43,
.profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
}
-TEST(gl_basic, glx_gles1_rgb)
+TEST(gl_basic, all_but_cgl_gles1_rgb)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1);
}
-TEST(gl_basic, glx_gles1_rgba)
+TEST(gl_basic, all_but_cgl_gles1_rgba)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
.alpha=true);
}
-TEST(gl_basic, glx_gles10)
+TEST(gl_basic, all_but_cgl_gles10)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=10,
- .alpha=true);
+ gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
+ .version=10,
+ .alpha=true);
}
-TEST(gl_basic, glx_gles1_fwdcompat_bad_attribute)
+TEST(gl_basic, all_but_cgl_gles11)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
+ .version=11,
+ .alpha=true);
}
-TEST(gl_basic, glx_gles11)
+TEST(gl_basic, all_but_cgl_gles1_fwdcompat_bad_attribute)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=11,
- .alpha=true);
+ gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
+ .forward_compatible=true,
+ .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
-TEST(gl_basic, glx_gles2_rgb)
+TEST(gl_basic, all_but_cgl_gles2_rgb)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2);
}
-TEST(gl_basic, glx_gles2_rgba)
+TEST(gl_basic, all_but_cgl_gles2_rgba)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
.alpha=true);
}
-TEST(gl_basic, glx_gles20)
+TEST(gl_basic, all_but_cgl_gles20)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
.version=20);
}
-TEST(gl_basic, glx_gles2_fwdcompat_bad_attribute)
+TEST(gl_basic, all_but_cgl_gles2_fwdcompat_bad_attribute)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
.forward_compatible=true,
.expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
-TEST(gl_basic, glx_gles3_rgb)
+TEST(gl_basic, all_but_cgl_gles3_rgb)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3);
}
-TEST(gl_basic, glx_gles3_rgba)
+TEST(gl_basic, all_but_cgl_gles3_rgba)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
.alpha=true);
}
-TEST(gl_basic, glx_gles30)
+TEST(gl_basic, all_but_cgl_gles30)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
.version=30);
}
-TEST(gl_basic, glx_gles3_fwdcompat_bad_attribute)
+TEST(gl_basic, all_but_cgl_gles3_fwdcompat_bad_attribute)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
.forward_compatible=true,
.expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
+#endif
-static void
-testsuite_glx(void)
-{
- TEST_RUN(gl_basic, glx_init);
-
- TEST_RUN(gl_basic, glx_gl_rgb);
- TEST_RUN(gl_basic, glx_gl_rgba);
- TEST_RUN(gl_basic, glx_gl_debug);
- TEST_RUN(gl_basic, glx_gl_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, glx_gl10);
- TEST_RUN(gl_basic, glx_gl11);
- TEST_RUN(gl_basic, glx_gl12);
- TEST_RUN(gl_basic, glx_gl13);
- TEST_RUN(gl_basic, glx_gl14);
- TEST_RUN(gl_basic, glx_gl15);
- TEST_RUN(gl_basic, glx_gl20);
- TEST_RUN(gl_basic, glx_gl21);
- TEST_RUN(gl_basic, glx_gl21_fwdcompat_bad_attribute);
- TEST_RUN(gl_basic, glx_gl30);
- TEST_RUN(gl_basic, glx_gl30_fwdcompat);
- TEST_RUN(gl_basic, glx_gl31);
- TEST_RUN(gl_basic, glx_gl31_fwdcompat);
-
- TEST_RUN(gl_basic, glx_gl32_core);
- TEST_RUN(gl_basic, glx_gl32_core_fwdcompat);
- TEST_RUN(gl_basic, glx_gl33_core);
- TEST_RUN(gl_basic, glx_gl40_core);
- TEST_RUN(gl_basic, glx_gl41_core);
- TEST_RUN(gl_basic, glx_gl42_core);
- TEST_RUN(gl_basic, glx_gl43_core);
-
- TEST_RUN(gl_basic, glx_gl32_compat);
- TEST_RUN(gl_basic, glx_gl33_compat);
- TEST_RUN(gl_basic, glx_gl40_compat);
- TEST_RUN(gl_basic, glx_gl41_compat);
- TEST_RUN(gl_basic, glx_gl42_compat);
- TEST_RUN(gl_basic, glx_gl43_compat);
-
- TEST_RUN(gl_basic, glx_gles1_rgb);
- TEST_RUN(gl_basic, glx_gles1_rgba);
- TEST_RUN(gl_basic, glx_gles1_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, glx_gles10);
- TEST_RUN(gl_basic, glx_gles11);
-
- TEST_RUN(gl_basic, glx_gles2_rgb);
- TEST_RUN(gl_basic, glx_gles2_rgba);
- TEST_RUN(gl_basic, glx_gles2_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, glx_gles20);
-
- TEST_RUN(gl_basic, glx_gles3_rgb);
- TEST_RUN(gl_basic, glx_gles3_rgba);
- TEST_RUN(gl_basic, glx_gles3_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, glx_gles30);
-}
-#endif // WAFFLE_HAS_GLX
-
-#ifdef WAFFLE_HAS_WAYLAND
-TEST(gl_basic, wayland_init)
-{
- gl_basic_init(WAFFLE_PLATFORM_WAYLAND);
-}
-
-TEST(gl_basic, wayland_gl_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL);
-}
-
-TEST(gl_basic, wayland_gl_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .alpha=true);
-}
-
-TEST(gl_basic, wayland_gl_debug)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .debug=true);
-}
-
-TEST(gl_basic, wayland_gl_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
-
-TEST(gl_basic, wayland_gl10)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=10);
-}
-
-TEST(gl_basic, wayland_gl11)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=11);
-}
-
-TEST(gl_basic, wayland_gl12)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=12);
-}
-
-TEST(gl_basic, wayland_gl13)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=13);
-}
-
-TEST(gl_basic, wayland_gl14)
+#ifdef WAFFLE_HAS_CGL
+TEST(gl_basic, cgl_init)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=14);
+ gl_basic_init(WAFFLE_PLATFORM_CGL);
}
-TEST(gl_basic, wayland_gl15)
+TEST(gl_basic, cgl_gles1_unsupported)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=15);
+ gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl20)
+TEST(gl_basic, cgl_gles2_unsupported)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=20);
+ gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl21)
+TEST(gl_basic, cgl_gl_debug_is_unsupported)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21);
+ .debug=true,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl21_fwdcompat_bad_attribute)
+TEST(gl_basic, cgl_gl_fwdcompat_bad_attribute)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21,
.forward_compatible=true,
.expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
}
-TEST(gl_basic, wayland_gl30)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=30);
-}
-
-TEST(gl_basic, wayland_gl30_fwdcompat)
+TEST(gl_basic, cgl_gl30)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=30,
- .forward_compatible=true);
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl31)
+TEST(gl_basic, cgl_gl31)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=31);
}
-TEST(gl_basic, wayland_gl31_fwdcompat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=31,
- .forward_compatible=true);
-}
-
-TEST(gl_basic, wayland_gl32_core)
+TEST(gl_basic, cgl_gl32_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=32,
.profile=WAFFLE_CONTEXT_CORE_PROFILE);
}
-TEST(gl_basic, wayland_gl32_core_fwdcompat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .forward_compatible=true);
-}
-
-TEST(gl_basic, wayland_gl33_core)
+TEST(gl_basic, cgl_gl33_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=33,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
+ .profile=WAFFLE_CONTEXT_CORE_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl40_core)
+TEST(gl_basic, cgl_gl40_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=40,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
+ .profile=WAFFLE_CONTEXT_CORE_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl41_core)
+TEST(gl_basic, cgl_gl41_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=41,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
+ .profile=WAFFLE_CONTEXT_CORE_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl42_core)
+TEST(gl_basic, cgl_gl42_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=42,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
+ .profile=WAFFLE_CONTEXT_CORE_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl43_core)
+TEST(gl_basic, cgl_gl43_core)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=43,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
+ .profile=WAFFLE_CONTEXT_CORE_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl32_compat)
+TEST(gl_basic, cgl_gl32_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=32,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl33_compat)
+TEST(gl_basic, cgl_gl33_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=33,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl40_compat)
+TEST(gl_basic, cgl_gl40_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=40,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl41_compat)
+TEST(gl_basic, cgl_gl41_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=41,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl42_compat)
+TEST(gl_basic, cgl_gl42_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=42,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gl43_compat)
+TEST(gl_basic, cgl_gl43_compat)
{
gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
.version=43,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, wayland_gles1_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1);
-}
-
-TEST(gl_basic, wayland_gles1_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .alpha=true);
+ .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE,
+ .expect_error=WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM);
}
-TEST(gl_basic, wayland_gles10)
+static void
+testsuite_cgl(void)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=10,
- .alpha=true);
-}
+ TEST_RUN(gl_basic, cgl_init);
-TEST(gl_basic, wayland_gles1_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
+ TEST_RUN(gl_basic, cgl_gles1_unsupported);
+ TEST_RUN(gl_basic, cgl_gles2_unsupported);
-TEST(gl_basic, wayland_gles11)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=11,
- .alpha=true);
-}
+ TEST_RUN2(gl_basic, cgl_gl_rgb, all_gl_rgb);
+ TEST_RUN2(gl_basic, cgl_gl_rgba, all_gl_rgba);
-TEST(gl_basic, wayland_gles2_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2);
-}
+ TEST_RUN(gl_basic, cgl_gl_debug_is_unsupported);
+ TEST_RUN(gl_basic, cgl_gl_fwdcompat_bad_attribute);
-TEST(gl_basic, wayland_gles2_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .alpha=true);
-}
+ TEST_RUN2(gl_basic, cgl_gl10, all_gl10);
+ TEST_RUN2(gl_basic, cgl_gl11, all_gl11);
+ TEST_RUN2(gl_basic, cgl_gl12, all_gl12);
+ TEST_RUN2(gl_basic, cgl_gl13, all_gl13);
+ TEST_RUN2(gl_basic, cgl_gl14, all_gl14);
+ TEST_RUN2(gl_basic, cgl_gl15, all_gl15);
+ TEST_RUN2(gl_basic, cgl_gl20, all_gl20);
+ TEST_RUN2(gl_basic, cgl_gl21, all_gl21);
+ TEST_RUN2(gl_basic, cgl_gl21_fwdcompat_bad_attribute, all_gl21_fwdcompat_bad_attribute);
+ TEST_RUN(gl_basic, cgl_gl30);
+ TEST_RUN(gl_basic, cgl_gl31);
-TEST(gl_basic, wayland_gles20)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .version=20);
-}
+ TEST_RUN(gl_basic, cgl_gl32_core);
+ TEST_RUN(gl_basic, cgl_gl33_core);
+ TEST_RUN(gl_basic, cgl_gl40_core);
+ TEST_RUN(gl_basic, cgl_gl41_core);
+ TEST_RUN(gl_basic, cgl_gl42_core);
+ TEST_RUN(gl_basic, cgl_gl43_core);
-TEST(gl_basic, wayland_gles2_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
+ TEST_RUN(gl_basic, cgl_gl32_compat);
+ TEST_RUN(gl_basic, cgl_gl33_compat);
+ TEST_RUN(gl_basic, cgl_gl40_compat);
+ TEST_RUN(gl_basic, cgl_gl41_compat);
+ TEST_RUN(gl_basic, cgl_gl42_compat);
+ TEST_RUN(gl_basic, cgl_gl43_compat);
}
+#endif // WAFFLE_HAS_CGL
-TEST(gl_basic, wayland_gles3_rgb)
+#ifdef WAFFLE_HAS_GLX
+TEST(gl_basic, glx_init)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3);
+ gl_basic_init(WAFFLE_PLATFORM_GLX);
}
-TEST(gl_basic, wayland_gles3_rgba)
+static void
+testsuite_glx(void)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .alpha=true);
-}
+ TEST_RUN(gl_basic, glx_init);
-TEST(gl_basic, wayland_gles30)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .version=30);
+ TEST_RUN2(gl_basic, glx_gl_rgb, all_gl_rgb);
+ TEST_RUN2(gl_basic, glx_gl_rgba, all_gl_rgb);
+ TEST_RUN2(gl_basic, glx_gl_debug, all_but_cgl_gl_debug);
+ TEST_RUN2(gl_basic, glx_gl_fwdcompat_bad_attribute, all_but_cgl_gl_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, glx_gl10, all_gl10);
+ TEST_RUN2(gl_basic, glx_gl11, all_gl11);
+ TEST_RUN2(gl_basic, glx_gl12, all_gl12);
+ TEST_RUN2(gl_basic, glx_gl13, all_gl13);
+ TEST_RUN2(gl_basic, glx_gl14, all_gl14);
+ TEST_RUN2(gl_basic, glx_gl15, all_gl15);
+ TEST_RUN2(gl_basic, glx_gl20, all_gl20);
+ TEST_RUN2(gl_basic, glx_gl21, all_gl21);
+ TEST_RUN2(gl_basic, glx_gl21_fwdcompat_bad_attribute, all_gl21_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, glx_gl30, all_but_cgl_gl30);
+ TEST_RUN2(gl_basic, glx_gl30_fwdcompat, all_but_cgl_gl30_fwdcompat);
+ TEST_RUN2(gl_basic, glx_gl31, all_but_cgl_gl31);
+ TEST_RUN2(gl_basic, glx_gl31_fwdcompat, all_but_cgl_gl31_fwdcompat);
+
+ TEST_RUN2(gl_basic, glx_gl32_core, all_but_cgl_gl32_core);
+ TEST_RUN2(gl_basic, glx_gl32_core_fwdcompat, all_but_cgl_gl32_core_fwdcompat);
+ TEST_RUN2(gl_basic, glx_gl33_core, all_but_cgl_gl33_core);
+ TEST_RUN2(gl_basic, glx_gl40_core, all_but_cgl_gl40_core);
+ TEST_RUN2(gl_basic, glx_gl41_core, all_but_cgl_gl41_core);
+ TEST_RUN2(gl_basic, glx_gl42_core, all_but_cgl_gl42_core);
+ TEST_RUN2(gl_basic, glx_gl43_core, all_but_cgl_gl43_core);
+
+ TEST_RUN2(gl_basic, glx_gl32_compat, all_but_cgl_gl32_compat);
+ TEST_RUN2(gl_basic, glx_gl33_compat, all_but_cgl_gl33_compat);
+ TEST_RUN2(gl_basic, glx_gl40_compat, all_but_cgl_gl40_compat);
+ TEST_RUN2(gl_basic, glx_gl41_compat, all_but_cgl_gl41_compat);
+ TEST_RUN2(gl_basic, glx_gl42_compat, all_but_cgl_gl42_compat);
+ TEST_RUN2(gl_basic, glx_gl43_compat, all_but_cgl_gl43_compat);
+
+ TEST_RUN2(gl_basic, glx_gles1_rgb, all_but_cgl_gles1_rgb);
+ TEST_RUN2(gl_basic, glx_gles1_rgba, all_but_cgl_gles1_rgba);
+ TEST_RUN2(gl_basic, glx_gles1_fwdcompat_bad_attribute, all_but_cgl_gles1_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, glx_gles10, all_but_cgl_gles10);
+ TEST_RUN2(gl_basic, glx_gles11, all_but_cgl_gles10);
+
+ TEST_RUN2(gl_basic, glx_gles2_rgb, all_but_cgl_gles2_rgb);
+ TEST_RUN2(gl_basic, glx_gles2_rgba, all_but_cgl_gles2_rgba);
+ TEST_RUN2(gl_basic, glx_gles2_fwdcompat_bad_attribute, all_but_cgl_gles2_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, glx_gles20, all_but_cgl_gles20);
+
+ TEST_RUN2(gl_basic, glx_gles3_rgb, all_but_cgl_gles3_rgb);
+ TEST_RUN2(gl_basic, glx_gles3_rgba, all_but_cgl_gles3_rgba);
+ TEST_RUN2(gl_basic, glx_gles3_fwdcompat_bad_attribute, all_but_cgl_gles3_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, glx_gles30, all_but_cgl_gles30);
}
+#endif // WAFFLE_HAS_GLX
-TEST(gl_basic, wayland_gles3_fwdcompat_bad_attribute)
+#ifdef WAFFLE_HAS_WAYLAND
+TEST(gl_basic, wayland_init)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
+ gl_basic_init(WAFFLE_PLATFORM_WAYLAND);
}
static void
@@ -1210,58 +890,60 @@ testsuite_wayland(void)
{
TEST_RUN(gl_basic, wayland_init);
- TEST_RUN(gl_basic, wayland_gl_rgb);
- TEST_RUN(gl_basic, wayland_gl_rgba);
- TEST_RUN(gl_basic, wayland_gl_debug);
- TEST_RUN(gl_basic, wayland_gl_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, wayland_gl10);
- TEST_RUN(gl_basic, wayland_gl11);
- TEST_RUN(gl_basic, wayland_gl12);
- TEST_RUN(gl_basic, wayland_gl13);
- TEST_RUN(gl_basic, wayland_gl14);
- TEST_RUN(gl_basic, wayland_gl15);
- TEST_RUN(gl_basic, wayland_gl20);
- TEST_RUN(gl_basic, wayland_gl21);
- TEST_RUN(gl_basic, wayland_gl21_fwdcompat_bad_attribute);
- TEST_RUN(gl_basic, wayland_gl30);
- TEST_RUN(gl_basic, wayland_gl30_fwdcompat);
- TEST_RUN(gl_basic, wayland_gl31);
- TEST_RUN(gl_basic, wayland_gl31_fwdcompat);
-
- TEST_RUN(gl_basic, wayland_gl32_core);
- TEST_RUN(gl_basic, wayland_gl32_core_fwdcompat);
- TEST_RUN(gl_basic, wayland_gl33_core);
- TEST_RUN(gl_basic, wayland_gl40_core);
- TEST_RUN(gl_basic, wayland_gl41_core);
- TEST_RUN(gl_basic, wayland_gl42_core);
- TEST_RUN(gl_basic, wayland_gl43_core);
-
- TEST_RUN(gl_basic, wayland_gl32_compat);
- TEST_RUN(gl_basic, wayland_gl33_compat);
- TEST_RUN(gl_basic, wayland_gl40_compat);
- TEST_RUN(gl_basic, wayland_gl41_compat);
- TEST_RUN(gl_basic, wayland_gl42_compat);
- TEST_RUN(gl_basic, wayland_gl43_compat);
-
- TEST_RUN(gl_basic, wayland_gles1_rgb);
- TEST_RUN(gl_basic, wayland_gles1_rgba);
- TEST_RUN(gl_basic, wayland_gles1_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, wayland_gles10);
- TEST_RUN(gl_basic, wayland_gles11);
-
- TEST_RUN(gl_basic, wayland_gles2_rgb);
- TEST_RUN(gl_basic, wayland_gles2_rgba);
- TEST_RUN(gl_basic, wayland_gles2_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, wayland_gles20);
-
- TEST_RUN(gl_basic, wayland_gles3_rgb);
- TEST_RUN(gl_basic, wayland_gles3_rgba);
- TEST_RUN(gl_basic, wayland_gles3_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, wayland_gles30);
+ TEST_RUN2(gl_basic, wayland_gl_rgb, all_gl_rgb);
+ TEST_RUN2(gl_basic, wayland_gl_rgba, all_gl_rgba);
+
+ TEST_RUN2(gl_basic, wayland_gl_debug, all_but_cgl_gl_debug);
+ TEST_RUN2(gl_basic, wayland_gl_fwdcompat_bad_attribute, all_but_cgl_gl_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, wayland_gl10, all_gl10);
+ TEST_RUN2(gl_basic, wayland_gl11, all_gl11);
+ TEST_RUN2(gl_basic, wayland_gl12, all_gl12);
+ TEST_RUN2(gl_basic, wayland_gl13, all_gl13);
+ TEST_RUN2(gl_basic, wayland_gl14, all_gl14);
+ TEST_RUN2(gl_basic, wayland_gl15, all_gl15);
+ TEST_RUN2(gl_basic, wayland_gl20, all_gl20);
+ TEST_RUN2(gl_basic, wayland_gl21, all_gl21);
+ TEST_RUN2(gl_basic, wayland_gl21_fwdcompat_bad_attribute, all_gl21_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, wayland_gl30, all_but_cgl_gl30);
+ TEST_RUN2(gl_basic, wayland_gl30_fwdcompat, all_but_cgl_gl30_fwdcompat);
+ TEST_RUN2(gl_basic, wayland_gl31, all_but_cgl_gl31);
+ TEST_RUN2(gl_basic, wayland_gl31_fwdcompat, all_but_cgl_gl31_fwdcompat);
+
+ TEST_RUN2(gl_basic, wayland_gl32_core, all_but_cgl_gl32_core);
+ TEST_RUN2(gl_basic, wayland_gl32_core_fwdcompat, all_but_cgl_gl32_core_fwdcompat);
+ TEST_RUN2(gl_basic, wayland_gl33_core, all_but_cgl_gl33_core);
+ TEST_RUN2(gl_basic, wayland_gl40_core, all_but_cgl_gl40_core);
+ TEST_RUN2(gl_basic, wayland_gl41_core, all_but_cgl_gl41_core);
+ TEST_RUN2(gl_basic, wayland_gl42_core, all_but_cgl_gl42_core);
+ TEST_RUN2(gl_basic, wayland_gl43_core, all_but_cgl_gl43_core);
+
+ TEST_RUN2(gl_basic, wayland_gl32_compat, all_but_cgl_gl32_compat);
+ TEST_RUN2(gl_basic, wayland_gl33_compat, all_but_cgl_gl33_compat);
+ TEST_RUN2(gl_basic, wayland_gl40_compat, all_but_cgl_gl40_compat);
+ TEST_RUN2(gl_basic, wayland_gl41_compat, all_but_cgl_gl41_compat);
+ TEST_RUN2(gl_basic, wayland_gl42_compat, all_but_cgl_gl42_compat);
+ TEST_RUN2(gl_basic, wayland_gl43_compat, all_but_cgl_gl43_compat);
+
+ TEST_RUN2(gl_basic, wayland_gles1_rgb, all_but_cgl_gles1_rgb);
+ TEST_RUN2(gl_basic, wayland_gles1_rgba, all_but_cgl_gles1_rgba);
+ TEST_RUN2(gl_basic, wayland_gles1_fwdcompat_bad_attribute, all_but_cgl_gles1_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, wayland_gles10, all_but_cgl_gles10);
+ TEST_RUN2(gl_basic, wayland_gles11, all_but_cgl_gles11);
+
+ TEST_RUN2(gl_basic, wayland_gles1_rgb, all_but_cgl_gles1_rgb);
+ TEST_RUN2(gl_basic, wayland_gles1_rgba, all_but_cgl_gles1_rgba);
+ TEST_RUN2(gl_basic, wayland_gles1_fwdcompat_bad_attribute, all_but_cgl_gles1_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, wayland_gles20, all_but_cgl_gles20);
+
+ TEST_RUN2(gl_basic, wayland_gles3_rgb, all_but_cgl_gles3_rgb);
+ TEST_RUN2(gl_basic, wayland_gles3_rgba, all_but_cgl_gles3_rgba);
+ TEST_RUN2(gl_basic, wayland_gles3_fwdcompat_bad_attribute, all_but_cgl_gles3_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, wayland_gles30, all_but_cgl_gles30);
}
#endif // WAFFLE_HAS_WAYLAND
@@ -1271,350 +953,198 @@ TEST(gl_basic, x11_egl_init)
gl_basic_init(WAFFLE_PLATFORM_X11_EGL);
}
-TEST(gl_basic, x11_egl_gl_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL);
-}
-
-TEST(gl_basic, x11_egl_gl_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .alpha=true);
-}
-
-TEST(gl_basic, x11_egl_gl_debug)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .debug=true);
-}
-
-TEST(gl_basic, x11_egl_gl_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
-
-TEST(gl_basic, x11_egl_gl10)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=10);
-}
-
-TEST(gl_basic, x11_egl_gl11)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=11);
-}
-
-TEST(gl_basic, x11_egl_gl12)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=12);
-}
-
-TEST(gl_basic, x11_egl_gl13)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=13);
-}
-
-TEST(gl_basic, x11_egl_gl14)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=14);
-}
-
-TEST(gl_basic, x11_egl_gl15)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=15);
-}
-
-TEST(gl_basic, x11_egl_gl20)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=20);
-}
-
-TEST(gl_basic, x11_egl_gl21)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21);
-}
-
-TEST(gl_basic, x11_egl_gl21_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=21,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
-
-TEST(gl_basic, x11_egl_gl30)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=30);
-}
-
-TEST(gl_basic, x11_egl_gl30_fwdcompat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=30,
- .forward_compatible=true);
-}
-
-TEST(gl_basic, x11_egl_gl31)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=31);
-}
-
-TEST(gl_basic, x11_egl_gl31_fwdcompat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=31,
- .forward_compatible=true);
-}
-
-TEST(gl_basic, x11_egl_gl32_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl32_core_fwdcompat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE,
- .forward_compatible=true);
-}
-
-TEST(gl_basic, x11_egl_gl33_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=33,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl40_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=40,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl41_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=41,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl42_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=42,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl43_core)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=43,
- .profile=WAFFLE_CONTEXT_CORE_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl32_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=32,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl33_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=33,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl40_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=40,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl41_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=41,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl42_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=42,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gl43_compat)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL,
- .version=43,
- .profile=WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
-}
-
-TEST(gl_basic, x11_egl_gles1_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1);
-}
-
-TEST(gl_basic, x11_egl_gles1_rgba)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .alpha=true);
-}
-
-TEST(gl_basic, x11_egl_gles10)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=10,
- .alpha=true);
-}
-
-TEST(gl_basic, x11_egl_gles11)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .version=11,
- .alpha=true);
-}
-
-TEST(gl_basic, x11_egl_gles1_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES1,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
-}
-
-TEST(gl_basic, x11_egl_gles2_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2);
-}
-
-TEST(gl_basic, x11_egl_gles2_rgba)
+static void
+testsuite_x11_egl(void)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .alpha=true);
-}
+ TEST_RUN(gl_basic, x11_egl_init);
-TEST(gl_basic, x11_egl_gles20)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .version=20);
+ TEST_RUN2(gl_basic, x11_egl_gl_rgb, all_gl_rgb);
+ TEST_RUN2(gl_basic, x11_egl_gl_rgba, all_gl_rgba);
+ TEST_RUN2(gl_basic, x11_egl_gl_debug, all_but_cgl_gl_debug);
+ TEST_RUN2(gl_basic, x11_egl_gl_fwdcompat_bad_attribute, all_but_cgl_gl_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, x11_egl_gl10, all_gl10);
+ TEST_RUN2(gl_basic, x11_egl_gl11, all_gl11);
+ TEST_RUN2(gl_basic, x11_egl_gl12, all_gl12);
+ TEST_RUN2(gl_basic, x11_egl_gl13, all_gl13);
+ TEST_RUN2(gl_basic, x11_egl_gl14, all_gl14);
+ TEST_RUN2(gl_basic, x11_egl_gl15, all_gl15);
+ TEST_RUN2(gl_basic, x11_egl_gl20, all_gl20);
+ TEST_RUN2(gl_basic, x11_egl_gl21, all_gl21);
+ TEST_RUN2(gl_basic, x11_egl_gl21_fwdcompat_bad_attribute, all_gl21_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, x11_egl_gl30, all_but_cgl_gl30);
+ TEST_RUN2(gl_basic, x11_egl_gl30_fwdcompat, all_but_cgl_gl30_fwdcompat);
+ TEST_RUN2(gl_basic, x11_egl_gl31, all_but_cgl_gl31);
+ TEST_RUN2(gl_basic, x11_egl_gl31_fwdcompat, all_but_cgl_gl31_fwdcompat);
+
+ TEST_RUN2(gl_basic, x11_egl_gl32_core, all_but_cgl_gl32_core);
+ TEST_RUN2(gl_basic, x11_egl_gl32_core_fwdcompat, all_but_cgl_gl32_core_fwdcompat);
+ TEST_RUN2(gl_basic, x11_egl_gl33_core, all_but_cgl_gl33_core);
+ TEST_RUN2(gl_basic, x11_egl_gl40_core, all_but_cgl_gl40_core);
+ TEST_RUN2(gl_basic, x11_egl_gl41_core, all_but_cgl_gl41_core);
+ TEST_RUN2(gl_basic, x11_egl_gl42_core, all_but_cgl_gl42_core);
+ TEST_RUN2(gl_basic, x11_egl_gl43_core, all_but_cgl_gl43_core);
+
+ TEST_RUN2(gl_basic, x11_egl_gl32_compat, all_but_cgl_gl32_compat);
+ TEST_RUN2(gl_basic, x11_egl_gl33_compat, all_but_cgl_gl33_compat);
+ TEST_RUN2(gl_basic, x11_egl_gl40_compat, all_but_cgl_gl40_compat);
+ TEST_RUN2(gl_basic, x11_egl_gl41_compat, all_but_cgl_gl41_compat);
+ TEST_RUN2(gl_basic, x11_egl_gl42_compat, all_but_cgl_gl42_compat);
+ TEST_RUN2(gl_basic, x11_egl_gl43_compat, all_but_cgl_gl43_compat);
+
+ TEST_RUN2(gl_basic, x11_egl_gles1_rgb, all_but_cgl_gles1_rgb);
+ TEST_RUN2(gl_basic, x11_egl_gles1_rgba, all_but_cgl_gles1_rgba);
+ TEST_RUN2(gl_basic, x11_egl_gles1_fwdcompat_bad_attribute, all_but_cgl_gles1_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, x11_egl_gles10, all_but_cgl_gles10);
+ TEST_RUN2(gl_basic, x11_egl_gles11, all_but_cgl_gles11);
+
+ TEST_RUN2(gl_basic, x11_egl_gles2_rgb, all_but_cgl_gles2_rgb);
+ TEST_RUN2(gl_basic, x11_egl_gles2_rgba, all_but_cgl_gles2_rgba);
+ TEST_RUN2(gl_basic, x11_egl_gles2_fwdcompat_bad_attribute, all_but_cgl_gles2_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, x11_egl_gles20, all_but_cgl_gles20);
+
+ TEST_RUN2(gl_basic, x11_egl_gles3_rgb, all_but_cgl_gles3_rgb);
+ TEST_RUN2(gl_basic, x11_egl_gles3_rgba, all_but_cgl_gles3_rgba);
+ TEST_RUN2(gl_basic, x11_egl_gles3_fwdcompat_bad_attribute, all_but_cgl_gles3_fwdcompat_bad_attribute);
+
+ TEST_RUN2(gl_basic, x11_egl_gles30, all_but_cgl_gles30);
}
+#endif // WAFFLE_HAS_X11_EGL
-TEST(gl_basic, x11_egl_gles2_fwdcompat_bad_attribute)
+#ifdef WAFFLE_HAS_WGL
+TEST(gl_basic, wgl_init)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES2,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
+ gl_basic_init(WAFFLE_PLATFORM_WGL);
}
-TEST(gl_basic, x11_egl_gles3_rgb)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3);
-}
+static void
+testsuite_wgl(void)
+{
+ TEST_RUN(gl_basic, wgl_init);
+
+ TEST_RUN(gl_basic, all_gl_rgb);
+ TEST_RUN(gl_basic, all_gl_rgba);
+ TEST_RUN(gl_basic, all_but_cgl_gl_debug);
+ TEST_RUN(gl_basic, all_but_cgl_gl_fwdcompat_bad_attribute);
+
+ TEST_RUN(gl_basic, all_gl10);
+ TEST_RUN(gl_basic, all_gl11);
+ TEST_RUN(gl_basic, all_gl12);
+ TEST_RUN(gl_basic, all_gl13);
+ TEST_RUN(gl_basic, all_gl14);
+ TEST_RUN(gl_basic, all_gl15);
+ TEST_RUN(gl_basic, all_gl20);
+ TEST_RUN(gl_basic, all_gl21);
+ TEST_RUN(gl_basic, all_gl21_fwdcompat_bad_attribute);
+
+ TEST_RUN(gl_basic, all_but_cgl_gl30);
+ TEST_RUN(gl_basic, all_but_cgl_gl30_fwdcompat);
+ TEST_RUN(gl_basic, all_but_cgl_gl31);
+ TEST_RUN(gl_basic, all_but_cgl_gl31_fwdcompat);
+
+ TEST_RUN(gl_basic, all_but_cgl_gl32_core);
+ TEST_RUN(gl_basic, all_but_cgl_gl32_core_fwdcompat);
+ TEST_RUN(gl_basic, all_but_cgl_gl33_core);
+ TEST_RUN(gl_basic, all_but_cgl_gl40_core);
+ TEST_RUN(gl_basic, all_but_cgl_gl41_core);
+ TEST_RUN(gl_basic, all_but_cgl_gl42_core);
+ TEST_RUN(gl_basic, all_but_cgl_gl43_core);
+
+ TEST_RUN(gl_basic, all_but_cgl_gl32_compat);
+ TEST_RUN(gl_basic, all_but_cgl_gl33_compat);
+ TEST_RUN(gl_basic, all_but_cgl_gl40_compat);
+ TEST_RUN(gl_basic, all_but_cgl_gl41_compat);
+ TEST_RUN(gl_basic, all_but_cgl_gl42_compat);
+ TEST_RUN(gl_basic, all_but_cgl_gl43_compat);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles1_rgb);
+ TEST_RUN(gl_basic, all_but_cgl_gles1_rgba);
+ TEST_RUN(gl_basic, all_but_cgl_gles1_fwdcompat_bad_attribute);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles10);
+ TEST_RUN(gl_basic, all_but_cgl_gles11);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles2_rgb);
+ TEST_RUN(gl_basic, all_but_cgl_gles2_rgba);
+ TEST_RUN(gl_basic, all_but_cgl_gles2_fwdcompat_bad_attribute);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles20);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles3_rgb);
+ TEST_RUN(gl_basic, all_but_cgl_gles3_rgba);
+ TEST_RUN(gl_basic, all_but_cgl_gles3_fwdcompat_bad_attribute);
+
+ TEST_RUN(gl_basic, all_but_cgl_gles30);
+}
+#endif // WAFFLE_HAS_WGL
-TEST(gl_basic, x11_egl_gles3_rgba)
+static void
+usage_error(void)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .alpha=true);
+ fprintf(stderr, "gl_basic_test: usage error\n");
+ exit(1);
}
-TEST(gl_basic, x11_egl_gles30)
+#ifdef _WIN32
+static DWORD __stdcall
+worker_thread(LPVOID lpParam)
{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .version=30);
-}
+ void (__stdcall *testsuite)(void) = lpParam;
+ void (__stdcall *testsuites[])(void) = {testsuite, 0};
+ int argc = 0;
+ DWORD num_failures = wt_main(&argc, NULL, testsuites);
-TEST(gl_basic, x11_egl_gles3_fwdcompat_bad_attribute)
-{
- gl_basic_draw(.api=WAFFLE_CONTEXT_OPENGL_ES3,
- .forward_compatible=true,
- .expect_error=WAFFLE_ERROR_BAD_ATTRIBUTE);
+ return num_failures;
}
+/// Run the testsuite in a separate thread. If the testsuite fails, then exit
+/// immediately.
static void
-testsuite_x11_egl(void)
+run_testsuite(void (*testsuite)(void))
{
- TEST_RUN(gl_basic, x11_egl_init);
-
- TEST_RUN(gl_basic, x11_egl_gl_rgb);
- TEST_RUN(gl_basic, x11_egl_gl_rgba);
- TEST_RUN(gl_basic, x11_egl_gl_debug);
- TEST_RUN(gl_basic, x11_egl_gl_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, x11_egl_gl10);
- TEST_RUN(gl_basic, x11_egl_gl11);
- TEST_RUN(gl_basic, x11_egl_gl12);
- TEST_RUN(gl_basic, x11_egl_gl13);
- TEST_RUN(gl_basic, x11_egl_gl14);
- TEST_RUN(gl_basic, x11_egl_gl15);
- TEST_RUN(gl_basic, x11_egl_gl20);
- TEST_RUN(gl_basic, x11_egl_gl21);
- TEST_RUN(gl_basic, x11_egl_gl21_fwdcompat_bad_attribute);
- TEST_RUN(gl_basic, x11_egl_gl30);
- TEST_RUN(gl_basic, x11_egl_gl30_fwdcompat);
- TEST_RUN(gl_basic, x11_egl_gl31);
- TEST_RUN(gl_basic, x11_egl_gl31_fwdcompat);
-
- TEST_RUN(gl_basic, x11_egl_gl32_core);
- TEST_RUN(gl_basic, x11_egl_gl32_core_fwdcompat);
- TEST_RUN(gl_basic, x11_egl_gl33_core);
- TEST_RUN(gl_basic, x11_egl_gl40_core);
- TEST_RUN(gl_basic, x11_egl_gl41_core);
- TEST_RUN(gl_basic, x11_egl_gl42_core);
- TEST_RUN(gl_basic, x11_egl_gl43_core);
-
- TEST_RUN(gl_basic, x11_egl_gl32_compat);
- TEST_RUN(gl_basic, x11_egl_gl33_compat);
- TEST_RUN(gl_basic, x11_egl_gl40_compat);
- TEST_RUN(gl_basic, x11_egl_gl41_compat);
- TEST_RUN(gl_basic, x11_egl_gl42_compat);
- TEST_RUN(gl_basic, x11_egl_gl43_compat);
-
- TEST_RUN(gl_basic, x11_egl_gles1_rgb);
- TEST_RUN(gl_basic, x11_egl_gles1_rgba);
- TEST_RUN(gl_basic, x11_egl_gles1_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, x11_egl_gles10);
- TEST_RUN(gl_basic, x11_egl_gles11);
-
- TEST_RUN(gl_basic, x11_egl_gles2_rgb);
- TEST_RUN(gl_basic, x11_egl_gles2_rgba);
- TEST_RUN(gl_basic, x11_egl_gles2_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, x11_egl_gles20);
-
- TEST_RUN(gl_basic, x11_egl_gles3_rgb);
- TEST_RUN(gl_basic, x11_egl_gles3_rgba);
- TEST_RUN(gl_basic, x11_egl_gles3_fwdcompat_bad_attribute);
-
- TEST_RUN(gl_basic, x11_egl_gles30);
+ HANDLE hThread;
+ DWORD dwThreadId;
+
+ hThread = CreateThread(NULL, 0, worker_thread, testsuite, 0, &dwThreadId);
+ if (hThread != NULL) {
+ // XXX: Add a decent timeout interval
+ if (WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0) {
+ DWORD exit_status;
+
+ if (GetExitCodeThread(hThread, &exit_status)) {
+ // exit_status is number of failures.
+ if (exit_status == 0) {
+ // All tests passed.
+ CloseHandle(hThread);
+ return;
+ }
+ else {
+ // Some tests failed. Don't run any more tests.
+ exit(exit_status);
+ // or exit process ?
+ }
+ }
+ else {
+ fprintf(stderr, "gl_basic_test: error: get thread exit status"
+ " failed (%lu)\n", GetLastError());
+ abort();
+ }
+ }
+ else {
+ fprintf(stderr, "gl_basic_test: error: wait for thread failed\n");
+ abort();
+ }
+ }
+ else {
+ fprintf(stderr, "gl_basic_test: error: CreateThread failed\n");
+ abort();
+ }
}
-#endif // WAFFLE_HAS_X11_EGL
-static void
-usage_error(void)
-{
- fprintf(stderr, "gl_basic_test: usage error\n");
- exit(1);
-}
+#else
/// Run the testsuite in a separate process. If the testsuite fails, then exit
/// immediately.
@@ -1662,6 +1192,8 @@ run_testsuite(void (*testsuite)(void))
}
}
+#endif // _WIN32
+
int
main(int argc, char *argv[])
{
@@ -1680,6 +1212,9 @@ main(int argc, char *argv[])
#ifdef WAFFLE_HAS_X11_EGL
run_testsuite(testsuite_x11_egl);
#endif
+#ifdef WAFFLE_HAS_WGL
+ run_testsuite(testsuite_wgl);
+#endif
return 0;
}
diff --git a/third_party/getopt/CMakeLists.txt b/third_party/getopt/CMakeLists.txt
new file mode 100644
index 0000000..e1a2c1c
--- /dev/null
+++ b/third_party/getopt/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+add_library(getopt_bundled STATIC EXCLUDE_FROM_ALL getopt_long.c)
+
+install(
+ FILES LICENSE
+ DESTINATION "${CMAKE_INSTALL_DOCDIR}"
+ RENAME LICENSE-getopt.txt
+ COMPONENT coredocs
+)
diff --git a/third_party/getopt/LICENSE b/third_party/getopt/LICENSE
new file mode 100644
index 0000000..1a9141b
--- /dev/null
+++ b/third_party/getopt/LICENSE
@@ -0,0 +1,45 @@
+Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+
+Copyright (c) 2000 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Dieter Baron and Thomas Klausner.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
diff --git a/third_party/getopt/getopt.h b/third_party/getopt/getopt.h
new file mode 100644
index 0000000..b6da6df
--- /dev/null
+++ b/third_party/getopt/getopt.h
@@ -0,0 +1,82 @@
+/* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */
+/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+/*
+ * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
+ */
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option {
+ /* name of long option */
+ const char *name;
+ /*
+ * one of no_argument, required_argument, and optional_argument:
+ * whether option takes an argument
+ */
+ int has_arg;
+ /* if not NULL, set *flag to val when option found */
+ int *flag;
+ /* if flag not NULL, value to set *flag to; else return value */
+ int val;
+};
+
+int getopt_long(int, char * const *, const char *,
+ const struct option *, int *);
+int getopt_long_only(int, char * const *, const char *,
+ const struct option *, int *);
+#ifndef _GETOPT_DEFINED_
+#define _GETOPT_DEFINED_
+int getopt(int, char * const *, const char *);
+int getsubopt(char **, char * const *, char **);
+
+extern char *optarg; /* getopt(3) external variables */
+extern int opterr;
+extern int optind;
+extern int optopt;
+extern int optreset;
+extern char *suboptarg; /* getsubopt(3) external variable */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_GETOPT_H_ */
diff --git a/third_party/getopt/getopt_long.c b/third_party/getopt/getopt_long.c
new file mode 100644
index 0000000..81268b8
--- /dev/null
+++ b/third_party/getopt/getopt_long.c
@@ -0,0 +1,511 @@
+/* $OpenBSD: getopt_long.c,v 1.24 2010/07/22 19:31:53 blambert Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, match;
+
+ current_argv = place;
+ match = -1;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ fprintf(stderr, ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ fprintf(stderr, noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ fprintf(stderr, recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ fprintf(stderr, illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ else if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ fprintf(stderr, illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ fprintf(stderr, recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ fprintf(stderr, recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
diff --git a/third_party/threads/CMakeLists.txt b/third_party/threads/CMakeLists.txt
new file mode 100644
index 0000000..1cc6092
--- /dev/null
+++ b/third_party/threads/CMakeLists.txt
@@ -0,0 +1,23 @@
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+if(WIN32)
+ set(threads_sources threads_win32.c)
+else()
+ set(threads_sources threads_posix.c)
+endif()
+
+add_library(threads_bundled STATIC EXCLUDE_FROM_ALL ${threads_sources})
+
+set_target_properties(threads_bundled
+ PROPERTIES
+ # This static library is linked into the shared libwaffle and the latter
+ # is PIC enabled thus we'll need to enable it here as well.
+ POSITION_INDEPENDENT_CODE ON
+ )
+
+install(
+ FILES LICENSE
+ DESTINATION "${CMAKE_INSTALL_DOCDIR}"
+ RENAME LICENSE-threads.txt
+ COMPONENT coredocs
+)
diff --git a/third_party/threads/LICENSE b/third_party/threads/LICENSE
new file mode 100644
index 0000000..0606f1b
--- /dev/null
+++ b/third_party/threads/LICENSE
@@ -0,0 +1,28 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
diff --git a/third_party/threads/threads.h b/third_party/threads/threads.h
new file mode 100644
index 0000000..4e7dba2
--- /dev/null
+++ b/third_party/threads/threads.h
@@ -0,0 +1,180 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef EMULATED_THREADS_H_INCLUDED_
+#define EMULATED_THREADS_H_INCLUDED_
+
+#include <time.h>
+
+#ifndef TIME_UTC
+#define TIME_UTC 1
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+
+// check configuration
+#if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600)
+#error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600
+#endif
+
+#if defined(EMULATED_THREADS_USE_NATIVE_CV) && (_WIN32_WINNT < 0x0600)
+#error EMULATED_THREADS_USE_NATIVE_CV requires _WIN32_WINNT>=0x0600
+#endif
+
+
+/*---------------------------- macros ----------------------------*/
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+#define ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT
+#else
+#define ONCE_FLAG_INIT {0}
+#endif
+#define TSS_DTOR_ITERATIONS 1
+
+// FIXME: temporary non-standard hack to ease transition
+#define _MTX_INITIALIZER_NP {{(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0}}
+
+/*---------------------------- types ----------------------------*/
+typedef struct cnd_t {
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ CONDITION_VARIABLE condvar;
+#else
+ int blocked;
+ int gone;
+ int to_unblock;
+ HANDLE sem_queue;
+ HANDLE sem_gate;
+ CRITICAL_SECTION monitor;
+#endif
+} cnd_t;
+
+typedef HANDLE thrd_t;
+
+typedef DWORD tss_t;
+
+typedef struct mtx_t {
+ CRITICAL_SECTION cs;
+} mtx_t;
+
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+typedef INIT_ONCE once_flag;
+#else
+typedef struct once_flag_t {
+ volatile LONG status;
+} once_flag;
+#endif
+
+#elif defined(__unix__) || defined(__unix)
+#include <pthread.h>
+
+/*---------------------------- macros ----------------------------*/
+#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
+#ifdef INIT_ONCE_STATIC_INIT
+#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
+#else
+#define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once.
+#endif
+
+// FIXME: temporary non-standard hack to ease transition
+#define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
+
+/*---------------------------- types ----------------------------*/
+typedef pthread_cond_t cnd_t;
+typedef pthread_t thrd_t;
+typedef pthread_key_t tss_t;
+typedef pthread_mutex_t mtx_t;
+typedef pthread_once_t once_flag;
+
+#else
+#error Not supported on this platform.
+#endif
+
+
+/*---------------------------- types ----------------------------*/
+typedef void (*tss_dtor_t)(void*);
+typedef int (*thrd_start_t)(void*);
+
+struct xtime {
+ time_t sec;
+ long nsec;
+};
+typedef struct xtime xtime;
+
+
+/*-------------------- enumeration constants --------------------*/
+enum {
+ mtx_plain = 0,
+ mtx_try = 1,
+ mtx_timed = 2,
+ mtx_recursive = 4
+};
+
+enum {
+ thrd_success = 0, // succeeded
+ thrd_timeout, // timeout
+ thrd_error, // failed
+ thrd_busy, // resource busy
+ thrd_nomem // out of memory
+};
+
+
+/*-------------------------- functions --------------------------*/
+void call_once(once_flag *flag, void (*func)(void));
+
+int cnd_broadcast(cnd_t *cond);
+void cnd_destroy(cnd_t *cond);
+int cnd_init(cnd_t *cond);
+int cnd_signal(cnd_t *cond);
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt);
+int cnd_wait(cnd_t *cond, mtx_t *mtx);
+
+void mtx_destroy(mtx_t *mtx);
+int mtx_init(mtx_t *mtx, int type);
+int mtx_lock(mtx_t *mtx);
+int mtx_timedlock(mtx_t *mtx, const xtime *xt);
+int mtx_trylock(mtx_t *mtx);
+int mtx_unlock(mtx_t *mtx);
+
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
+thrd_t thrd_current(void);
+int thrd_detach(thrd_t thr);
+int thrd_equal(thrd_t thr0, thrd_t thr1);
+void thrd_exit(int res);
+int thrd_join(thrd_t thr, int *res);
+void thrd_sleep(const xtime *xt);
+void thrd_yield(void);
+
+int tss_create(tss_t *key, tss_dtor_t dtor);
+void tss_delete(tss_t key);
+void *tss_get(tss_t key);
+int tss_set(tss_t key, void *val);
+
+int xtime_get(xtime *xt, int base);
+
+
+#endif /* EMULATED_THREADS_H_INCLUDED_ */
diff --git a/third_party/threads/threads_posix.c b/third_party/threads/threads_posix.c
new file mode 100644
index 0000000..5835e43
--- /dev/null
+++ b/third_party/threads/threads_posix.c
@@ -0,0 +1,325 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#ifndef assert
+#include <assert.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sched.h>
+
+/*
+Configuration macro:
+
+ EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ Use pthread_mutex_timedlock() for `mtx_timedlock()'
+ Otherwise use mtx_trylock() + *busy loop* emulation.
+*/
+#if !defined(__CYGWIN__) && !defined(ANDROID)
+#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+#endif
+
+#include "threads.h"
+
+
+/*
+Implementation limits:
+ - Conditionally emulation for "mutex with timeout"
+ (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)
+*/
+int mtx_trylock(mtx_t *mtx); // forward decl.
+void thrd_yield(void); // forward decl.
+
+struct impl_thrd_param {
+ thrd_start_t func;
+ void *arg;
+};
+
+static void *impl_thrd_routine(void *p)
+{
+ struct impl_thrd_param pack = *((struct impl_thrd_param *)p);
+ free(p);
+ return (void*)(intptr_t)pack.func(pack.arg);
+}
+
+
+/*--------------- 7.25.2 Initialization functions ---------------*/
+// 7.25.2.1
+void call_once(once_flag *flag, void (*func)(void))
+{
+ pthread_once(flag, func);
+}
+
+
+/*------------- 7.25.3 Condition variable functions -------------*/
+// 7.25.3.1
+int cnd_broadcast(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+ pthread_cond_broadcast(cond);
+ return thrd_success;
+}
+
+// 7.25.3.2
+void cnd_destroy(cnd_t *cond)
+{
+ assert(cond);
+ pthread_cond_destroy(cond);
+}
+
+// 7.25.3.3
+int cnd_init(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+ pthread_cond_init(cond, NULL);
+ return thrd_success;
+}
+
+// 7.25.3.4
+int cnd_signal(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+ pthread_cond_signal(cond);
+ return thrd_success;
+}
+
+// 7.25.3.5
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
+{
+ struct timespec abs_time;
+ int rt;
+ if (!cond || !mtx || !xt) return thrd_error;
+ rt = pthread_cond_timedwait(cond, mtx, &abs_time);
+ if (rt == ETIMEDOUT)
+ return thrd_busy;
+ return (rt == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.3.6
+int cnd_wait(cnd_t *cond, mtx_t *mtx)
+{
+ if (!cond || !mtx) return thrd_error;
+ pthread_cond_wait(cond, mtx);
+ return thrd_success;
+}
+
+
+/*-------------------- 7.25.4 Mutex functions --------------------*/
+// 7.25.4.1
+void mtx_destroy(mtx_t *mtx)
+{
+ assert(mtx);
+ pthread_mutex_destroy(mtx);
+}
+
+// 7.25.4.2
+int mtx_init(mtx_t *mtx, int type)
+{
+ pthread_mutexattr_t attr;
+ if (!mtx) return thrd_error;
+ if (type != mtx_plain && type != mtx_timed && type != mtx_try
+ && type != (mtx_plain|mtx_recursive)
+ && type != (mtx_timed|mtx_recursive)
+ && type != (mtx_try|mtx_recursive))
+ return thrd_error;
+ pthread_mutexattr_init(&attr);
+ if ((type & mtx_recursive) != 0) {
+#if defined(__linux__) || defined(__linux)
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+#else
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+#endif
+ }
+ pthread_mutex_init(mtx, &attr);
+ pthread_mutexattr_destroy(&attr);
+ return thrd_success;
+}
+
+// 7.25.4.3
+int mtx_lock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ pthread_mutex_lock(mtx);
+ return thrd_success;
+}
+
+// 7.25.4.4
+int mtx_timedlock(mtx_t *mtx, const xtime *xt)
+{
+ if (!mtx || !xt) return thrd_error;
+ {
+#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ struct timespec ts;
+ int rt;
+ ts.tv_sec = xt->sec;
+ ts.tv_nsec = xt->nsec;
+ rt = pthread_mutex_timedlock(mtx, &ts);
+ if (rt == 0)
+ return thrd_success;
+ return (rt == ETIMEDOUT) ? thrd_busy : thrd_error;
+#else
+ time_t expire = time(NULL);
+ expire += xt->sec;
+ while (mtx_trylock(mtx) != thrd_success) {
+ time_t now = time(NULL);
+ if (expire < now)
+ return thrd_busy;
+ // busy loop!
+ thrd_yield();
+ }
+ return thrd_success;
+#endif
+ }
+}
+
+// 7.25.4.5
+int mtx_trylock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
+}
+
+// 7.25.4.6
+int mtx_unlock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ pthread_mutex_unlock(mtx);
+ return thrd_success;
+}
+
+
+/*------------------- 7.25.5 Thread functions -------------------*/
+// 7.25.5.1
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
+{
+ struct impl_thrd_param *pack;
+ if (!thr) return thrd_error;
+ pack = malloc(sizeof(struct impl_thrd_param));
+ if (!pack) return thrd_nomem;
+ pack->func = func;
+ pack->arg = arg;
+ if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) {
+ free(pack);
+ return thrd_error;
+ }
+ return thrd_success;
+}
+
+// 7.25.5.2
+thrd_t thrd_current(void)
+{
+ return pthread_self();
+}
+
+// 7.25.5.3
+int thrd_detach(thrd_t thr)
+{
+ return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.5.4
+int thrd_equal(thrd_t thr0, thrd_t thr1)
+{
+ return pthread_equal(thr0, thr1);
+}
+
+// 7.25.5.5
+void thrd_exit(int res)
+{
+ pthread_exit((void*)(intptr_t)res);
+}
+
+// 7.25.5.6
+int thrd_join(thrd_t thr, int *res)
+{
+ void *code;
+ if (pthread_join(thr, &code) != 0)
+ return thrd_error;
+ if (res)
+ *res = (int)(intptr_t)code;
+ return thrd_success;
+}
+
+// 7.25.5.7
+void thrd_sleep(const xtime *xt)
+{
+ struct timespec req;
+ assert(xt);
+ req.tv_sec = xt->sec;
+ req.tv_nsec = xt->nsec;
+ nanosleep(&req, NULL);
+}
+
+// 7.25.5.8
+void thrd_yield(void)
+{
+ sched_yield();
+}
+
+
+/*----------- 7.25.6 Thread-specific storage functions -----------*/
+// 7.25.6.1
+int tss_create(tss_t *key, tss_dtor_t dtor)
+{
+ if (!key) return thrd_error;
+ return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.6.2
+void tss_delete(tss_t key)
+{
+ pthread_key_delete(key);
+}
+
+// 7.25.6.3
+void *tss_get(tss_t key)
+{
+ return pthread_getspecific(key);
+}
+
+// 7.25.6.4
+int tss_set(tss_t key, void *val)
+{
+ return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
+}
+
+
+/*-------------------- 7.25.7 Time functions --------------------*/
+// 7.25.6.1
+int xtime_get(xtime *xt, int base)
+{
+ if (!xt) return 0;
+ if (base == TIME_UTC) {
+ xt->sec = time(NULL);
+ xt->nsec = 0;
+ return base;
+ }
+ return 0;
+}
diff --git a/third_party/threads/threads_win32.c b/third_party/threads/threads_win32.c
new file mode 100644
index 0000000..76c2855
--- /dev/null
+++ b/third_party/threads/threads_win32.c
@@ -0,0 +1,527 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef assert
+#include <assert.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <process.h> // MSVCRT
+
+/*
+Configuration macro:
+
+ EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ Use native WindowsAPI one-time initialization function.
+ (requires WinVista or later)
+ Otherwise emulate by mtx_trylock() + *busy loop* for WinXP.
+
+ EMULATED_THREADS_USE_NATIVE_CV
+ Use native WindowsAPI condition variable object.
+ (requires WinVista or later)
+ Otherwise use emulated implementation for WinXP.
+
+ EMULATED_THREADS_TSS_DTOR_SLOTNUM
+ Max registerable TSS dtor number.
+*/
+
+// XXX: Retain XP compatability
+#if 0
+#if _WIN32_WINNT >= 0x0600
+// Prefer native WindowsAPI on newer environment.
+#define EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+#define EMULATED_THREADS_USE_NATIVE_CV
+#endif
+#endif
+#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE
+
+#include "threads.h"
+
+
+/*
+Implementation limits:
+ - Conditionally emulation for "Initialization functions"
+ (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro)
+ - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop*
+*/
+static void impl_tss_dtor_invoke(void); // forward decl.
+
+struct impl_thrd_param {
+ thrd_start_t func;
+ void *arg;
+};
+
+static unsigned __stdcall impl_thrd_routine(void *p)
+{
+ struct impl_thrd_param pack;
+ int code;
+ memcpy(&pack, p, sizeof(struct impl_thrd_param));
+ free(p);
+ code = pack.func(pack.arg);
+ impl_tss_dtor_invoke();
+ return (unsigned)code;
+}
+
+static DWORD impl_xtime2msec(const xtime *xt)
+{
+ return (DWORD)((xt->sec * 1000U) + (xt->nsec / 1000000L));
+}
+
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+struct impl_call_once_param { void (*func)(void); };
+static BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+{
+ struct impl_call_once_param *param = (struct impl_call_once_param*)Parameter;
+ (param->func)();
+ ((void)InitOnce); ((void)Context); // suppress warning
+ return TRUE;
+}
+#endif // ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+
+#ifndef EMULATED_THREADS_USE_NATIVE_CV
+/*
+Note:
+ The implementation of condition variable is ported from Boost.Interprocess
+ See http://www.boost.org/boost/interprocess/sync/windows/condition.hpp
+*/
+static void impl_cond_do_signal(cnd_t *cond, int broadcast)
+{
+ int nsignal = 0;
+
+ EnterCriticalSection(&cond->monitor);
+ if (cond->to_unblock != 0) {
+ if (cond->blocked == 0) {
+ LeaveCriticalSection(&cond->monitor);
+ return;
+ }
+ if (broadcast) {
+ cond->to_unblock += nsignal = cond->blocked;
+ cond->blocked = 0;
+ } else {
+ nsignal = 1;
+ cond->to_unblock++;
+ cond->blocked--;
+ }
+ } else if (cond->blocked > cond->gone) {
+ WaitForSingleObject(cond->sem_gate, INFINITE);
+ if (cond->gone != 0) {
+ cond->blocked -= cond->gone;
+ cond->gone = 0;
+ }
+ if (broadcast) {
+ nsignal = cond->to_unblock = cond->blocked;
+ cond->blocked = 0;
+ } else {
+ nsignal = cond->to_unblock = 1;
+ cond->blocked--;
+ }
+ }
+ LeaveCriticalSection(&cond->monitor);
+
+ if (0 < nsignal)
+ ReleaseSemaphore(cond->sem_queue, nsignal, NULL);
+}
+
+static int impl_cond_do_wait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
+{
+ int nleft = 0;
+ int ngone = 0;
+ int timeout = 0;
+ DWORD w;
+
+ WaitForSingleObject(cond->sem_gate, INFINITE);
+ cond->blocked++;
+ ReleaseSemaphore(cond->sem_gate, 1, NULL);
+
+ mtx_unlock(mtx);
+
+ w = WaitForSingleObject(cond->sem_queue, xt ? impl_xtime2msec(xt) : INFINITE);
+ timeout = (w == WAIT_TIMEOUT);
+
+ EnterCriticalSection(&cond->monitor);
+ if ((nleft = cond->to_unblock) != 0) {
+ if (timeout) {
+ if (cond->blocked != 0) {
+ cond->blocked--;
+ } else {
+ cond->gone++;
+ }
+ }
+ if (--cond->to_unblock == 0) {
+ if (cond->blocked != 0) {
+ ReleaseSemaphore(cond->sem_gate, 1, NULL);
+ nleft = 0;
+ }
+ else if ((ngone = cond->gone) != 0) {
+ cond->gone = 0;
+ }
+ }
+ } else if (++cond->gone == INT_MAX/2) {
+ WaitForSingleObject(cond->sem_gate, INFINITE);
+ cond->blocked -= cond->gone;
+ ReleaseSemaphore(cond->sem_gate, 1, NULL);
+ cond->gone = 0;
+ }
+ LeaveCriticalSection(&cond->monitor);
+
+ if (nleft == 1) {
+ while (ngone--)
+ WaitForSingleObject(cond->sem_queue, INFINITE);
+ ReleaseSemaphore(cond->sem_gate, 1, NULL);
+ }
+
+ mtx_lock(mtx);
+ return timeout ? thrd_busy : thrd_success;
+}
+#endif // ifndef EMULATED_THREADS_USE_NATIVE_CV
+
+static struct impl_tss_dtor_entry {
+ tss_t key;
+ tss_dtor_t dtor;
+} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM];
+
+static int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor)
+{
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (!impl_tss_dtor_tbl[i].dtor)
+ break;
+ }
+ if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM)
+ return 1;
+ impl_tss_dtor_tbl[i].key = key;
+ impl_tss_dtor_tbl[i].dtor = dtor;
+ return 0;
+}
+
+static void impl_tss_dtor_invoke()
+{
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (impl_tss_dtor_tbl[i].dtor) {
+ void* val = tss_get(impl_tss_dtor_tbl[i].key);
+ if (val)
+ (impl_tss_dtor_tbl[i].dtor)(val);
+ }
+ }
+}
+
+
+/*--------------- 7.25.2 Initialization functions ---------------*/
+// 7.25.2.1
+void call_once(once_flag *flag, void (*func)(void))
+{
+ assert(flag && func);
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ {
+ struct impl_call_once_param param;
+ param.func = func;
+ InitOnceExecuteOnce(flag, impl_call_once_callback, (PVOID)&param, NULL);
+ }
+#else
+ if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) {
+ (func)();
+ InterlockedExchange(&flag->status, 2);
+ } else {
+ while (flag->status == 1) {
+ // busy loop!
+ thrd_yield();
+ }
+ }
+#endif
+}
+
+
+/*------------- 7.25.3 Condition variable functions -------------*/
+// 7.25.3.1
+int cnd_broadcast(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ WakeAllConditionVariable(&cond->condvar);
+#else
+ impl_cond_do_signal(cond, 1);
+#endif
+ return thrd_success;
+}
+
+// 7.25.3.2
+void cnd_destroy(cnd_t *cond)
+{
+ assert(cond);
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ // do nothing
+#else
+ CloseHandle(cond->sem_queue);
+ CloseHandle(cond->sem_gate);
+ DeleteCriticalSection(&cond->monitor);
+#endif
+}
+
+// 7.25.3.3
+int cnd_init(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ InitializeConditionVariable(&cond->condvar);
+#else
+ cond->blocked = 0;
+ cond->gone = 0;
+ cond->to_unblock = 0;
+ cond->sem_queue = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
+ cond->sem_gate = CreateSemaphore(NULL, 1, 1, NULL);
+ InitializeCriticalSection(&cond->monitor);
+#endif
+ return thrd_success;
+}
+
+// 7.25.3.4
+int cnd_signal(cnd_t *cond)
+{
+ if (!cond) return thrd_error;
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ WakeConditionVariable(&cond->condvar);
+#else
+ impl_cond_do_signal(cond, 0);
+#endif
+ return thrd_success;
+}
+
+// 7.25.3.5
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
+{
+ if (!cond || !mtx || !xt) return thrd_error;
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ if (SleepConditionVariableCS(&cond->condvar, &mtx->cs, impl_xtime2msec(xt)))
+ return thrd_success;
+ return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error;
+#else
+ return impl_cond_do_wait(cond, mtx, xt);
+#endif
+}
+
+// 7.25.3.6
+int cnd_wait(cnd_t *cond, mtx_t *mtx)
+{
+ if (!cond || !mtx) return thrd_error;
+#ifdef EMULATED_THREADS_USE_NATIVE_CV
+ SleepConditionVariableCS(&cond->condvar, &mtx->cs, INFINITE);
+#else
+ impl_cond_do_wait(cond, mtx, NULL);
+#endif
+ return thrd_success;
+}
+
+
+/*-------------------- 7.25.4 Mutex functions --------------------*/
+// 7.25.4.1
+void mtx_destroy(mtx_t *mtx)
+{
+ assert(mtx);
+ DeleteCriticalSection(&mtx->cs);
+}
+
+// 7.25.4.2
+int mtx_init(mtx_t *mtx, int type)
+{
+ if (!mtx) return thrd_error;
+ if (type != mtx_plain && type != mtx_timed && type != mtx_try
+ && type != (mtx_plain|mtx_recursive)
+ && type != (mtx_timed|mtx_recursive)
+ && type != (mtx_try|mtx_recursive))
+ return thrd_error;
+ InitializeCriticalSection(&mtx->cs);
+ return thrd_success;
+}
+
+// 7.25.4.3
+int mtx_lock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ EnterCriticalSection(&mtx->cs);
+ return thrd_success;
+}
+
+// 7.25.4.4
+int mtx_timedlock(mtx_t *mtx, const xtime *xt)
+{
+ time_t expire, now;
+ if (!mtx || !xt) return thrd_error;
+ expire = time(NULL);
+ expire += xt->sec;
+ while (mtx_trylock(mtx) != thrd_success) {
+ now = time(NULL);
+ if (expire < now)
+ return thrd_busy;
+ // busy loop!
+ thrd_yield();
+ }
+ return thrd_success;
+}
+
+// 7.25.4.5
+int mtx_trylock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ return TryEnterCriticalSection(&mtx->cs) ? thrd_success : thrd_busy;
+}
+
+// 7.25.4.6
+int mtx_unlock(mtx_t *mtx)
+{
+ if (!mtx) return thrd_error;
+ LeaveCriticalSection(&mtx->cs);
+ return thrd_success;
+}
+
+
+/*------------------- 7.25.5 Thread functions -------------------*/
+// 7.25.5.1
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
+{
+ struct impl_thrd_param *pack;
+ uintptr_t handle;
+ if (!thr) return thrd_error;
+ pack = malloc(sizeof(struct impl_thrd_param));
+ if (!pack) return thrd_nomem;
+ pack->func = func;
+ pack->arg = arg;
+ handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL);
+ if (handle == 0) {
+ if (errno == EAGAIN || errno == EACCES)
+ return thrd_nomem;
+ return thrd_error;
+ }
+ *thr = (thrd_t)handle;
+ return thrd_success;
+}
+
+// 7.25.5.2
+thrd_t thrd_current(void)
+{
+ return GetCurrentThread();
+}
+
+// 7.25.5.3
+int thrd_detach(thrd_t thr)
+{
+ CloseHandle(thr);
+ return thrd_success;
+}
+
+// 7.25.5.4
+int thrd_equal(thrd_t thr0, thrd_t thr1)
+{
+ return (thr0 == thr1);
+}
+
+// 7.25.5.5
+void thrd_exit(int res)
+{
+ impl_tss_dtor_invoke();
+ _endthreadex((unsigned)res);
+}
+
+// 7.25.5.6
+int thrd_join(thrd_t thr, int *res)
+{
+ DWORD w, code;
+ w = WaitForSingleObject(thr, INFINITE);
+ if (w != WAIT_OBJECT_0)
+ return thrd_error;
+ if (res) {
+ if (!GetExitCodeThread(thr, &code)) {
+ CloseHandle(thr);
+ return thrd_error;
+ }
+ *res = (int)code;
+ }
+ CloseHandle(thr);
+ return thrd_success;
+}
+
+// 7.25.5.7
+void thrd_sleep(const xtime *xt)
+{
+ assert(xt);
+ Sleep(impl_xtime2msec(xt));
+}
+
+// 7.25.5.8
+void thrd_yield(void)
+{
+ SwitchToThread();
+}
+
+
+/*----------- 7.25.6 Thread-specific storage functions -----------*/
+// 7.25.6.1
+int tss_create(tss_t *key, tss_dtor_t dtor)
+{
+ if (!key) return thrd_error;
+ *key = TlsAlloc();
+ if (dtor) {
+ if (impl_tss_dtor_register(*key, dtor)) {
+ TlsFree(*key);
+ return thrd_error;
+ }
+ }
+ return (*key != 0xFFFFFFFF) ? thrd_success : thrd_error;
+}
+
+// 7.25.6.2
+void tss_delete(tss_t key)
+{
+ TlsFree(key);
+}
+
+// 7.25.6.3
+void *tss_get(tss_t key)
+{
+ return TlsGetValue(key);
+}
+
+// 7.25.6.4
+int tss_set(tss_t key, void *val)
+{
+ return TlsSetValue(key, val) ? thrd_success : thrd_error;
+}
+
+
+/*-------------------- 7.25.7 Time functions --------------------*/
+// 7.25.6.1
+int xtime_get(xtime *xt, int base)
+{
+ if (!xt) return 0;
+ if (base == TIME_UTC) {
+ xt->sec = time(NULL);
+ xt->nsec = 0;
+ return base;
+ }
+ return 0;
+}