GL: Switch from GLEW to Epoxy

Epoxy automatically fetches the extension functions on demand, including
the GLX context creation functions. This means that you can't test the
function pointers for NULL anymore, because they're always set to a
resolver function until the first call. Instead, you have to check for the
availability of an extension by the extension's name. Thanks to Isilkor for
catching these.

On windows, epoxy invalidates all extension function pointers when the
GL context changes. This means we need to have an active context at all
times we call an extension function (like wglGetPixelFormatAttribivARB)
or else the code will jump to an invalid pointer. On the other hand, we do
not need to make it reinitialize the pointers ourselves.

Epoxy automatically uses an alias for a function if the requested name is
not available, like glDebugMessageCallbackARB instead of
glDebugMessageCallback. It also does not have the problem with varying
parameter types for that function. So switch to it while removing
GLDEBUGPROCARB_USERPARAM_IS_CONST.
epoxy
Günther Brammer 2016-01-29 18:29:46 +01:00
parent 408dfff96e
commit d4634526fd
16 changed files with 72 additions and 197 deletions

View File

@ -251,14 +251,8 @@ endif()
include_directories(SYSTEM ${TinyXML_INCLUDE_DIRS})
find_package(OpenGL)
find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_DIRS})
add_definitions(${GLEW_DEFINITIONS})
# On some platforms, GLEW declares the userParam parameter of
# GLDEBUGPROCARB as const void *, and on other platforms, it's void *.
# Test which one works here.
set(CMAKE_REQUIRED_INCLUDES "${GLEW_INCLUDE_DIRS}")
CHECK_CXX_SOURCE_COMPILES("#include <GL/glew.h>\nvoid GLAPIENTRY OpenGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam) {}\nint main() { GLDEBUGPROCARB proc = &OpenGLDebugProc; }" GLDEBUGPROCARB_USERPARAM_IS_CONST)
find_package(Epoxy REQUIRED)
include_directories(${Epoxy_INCLUDE_DIRS})
if(USE_GTK AND UNIX)
FINDLIB(X11_LIBRARIES X11)
@ -1096,7 +1090,7 @@ target_link_libraries(openclonk
${SDL2_LIBRARIES}
${Audio_LIBRARIES}
${GETOPT_LIBRARIES}
${GLEW_LIBRARIES}
${Epoxy_LIBRARIES}
${OPENGL_LIBRARIES}
${TinyXML_LIBRARIES}
${X11_LIBRARIES}

View File

@ -0,0 +1,31 @@
# OpenClonk, http://www.openclonk.org
#
# Copyright (c) 2016, The OpenClonk Team and contributors
#
# Distributed under the terms of the ISC license; see accompanying file
# "COPYING" for details.
#
# "Clonk" is a registered trademark of Matthes Bender, used with permission.
# See accompanying file "TRADEMARK" for details.
#
# To redistribute this file separately, substitute the full license texts
# for the above references.
# Locate Epoxy.
# This module defines
# Epoxy_INCLUDE_DIRS - a list of directories that need to be added to the include path
# Epoxy_LIBRARIES - a list of libraries to link against to use Epoxy
# Epoxy_FOUND - if false, Epoxy cannot be used
find_path(Epoxy_INCLUDE_DIR epoxy/gl.h)
mark_as_advanced(Epoxy_INCLUDE_DIR)
find_library(Epoxy_LIBRARY epoxy)
mark_as_advanced(Epoxy_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Epoxy REQUIRED_VARS Epoxy_LIBRARY Epoxy_INCLUDE_DIR)
if (Epoxy_FOUND)
set(Epoxy_LIBRARIES "${Epoxy_LIBRARY}")
set(Epoxy_INCLUDE_DIRS "${Epoxy_INCLUDE_DIR}")
endif()

View File

@ -1,63 +0,0 @@
# OpenClonk, http://www.openclonk.org
#
# Copyright (c) 2015, The OpenClonk Team and contributors
#
# Distributed under the terms of the ISC license; see accompanying file
# "COPYING" for details.
#
# "Clonk" is a registered trademark of Matthes Bender, used with permission.
# See accompanying file "TRADEMARK" for details.
#
# To redistribute this file separately, substitute the full license texts
# for the above references.
# Locate GLEW.
# This module defines
# GLEW_INCLUDE_DIRS - a list of directories that need to be added to the include path
# GLEW_LIBRARIES - a list of libraries to link against to use GLEW
# GLEW_DEFINITIONS - a list of compile-time macros that need to be defined to use GLEW
# GLEW_FOUND - if false, GLEW cannot be used
find_path(GLEW_INCLUDE_DIR GL/glew.h PATH_SUFFIXES)
mark_as_advanced(GLEW_INCLUDE_DIR)
# Read GLEW version from header
if (GLEW_INCLUDE_DIR AND EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h")
file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" glew_version_str REGEX "^VERSION .+")
string(REGEX REPLACE "^VERSION (.+)" "\\1" GLEW_VERSION_STRING "${glew_version_str}")
unset(glew_version_str)
endif()
# On OS other than Windows, it doesn't matter whether we confuse the shared
# library and the static one. On Windows, we need to #define GLEW_STATIC if
# (and only if) we're linking against the static library. "glew32" may match
# the static library on MinGW, so we have to test for that explicitly.
find_library(GLEW_STATIC_LIBRARY glew32s)
mark_as_advanced(GLEW_STATIC_LIBRARY)
find_library(GLEW_SHARED_LIBRARY NAMES GLEW glew32)
mark_as_advanced(GLEW_SHARED_LIBRARY)
if (GLEW_SHARED_LIBRARY)
set(GLEW_LIBRARY "${GLEW_SHARED_LIBRARY}")
if (WIN32 AND MINGW AND GLEW_SHARED_LIBRARY MATCHES "\\.a$")
# not actually a shared library
set(GLEW_DEFINITIONS "-DGLEW_STATIC")
else()
set(GLEW_DEFINITIONS)
endif()
elseif (GLEW_STATIC_LIBRARY)
set(GLEW_LIBRARY "${GLEW_STATIC_LIBRARY}")
set(GLEW_DEFINITIONS "-DGLEW_STATIC")
endif()
include(FindPackageHandleStandardArgs)
if (NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.3")
find_package_handle_standard_args(GLEW VERSION_VAR GLEW_VERSION_STRING REQUIRED_VARS GLEW_LIBRARY GLEW_INCLUDE_DIR)
else()
find_package_handle_standard_args(GLEW GLEW_LIBRARY GLEW_INCLUDE_DIR)
endif()
if (GLEW_FOUND)
set(GLEW_LIBRARIES "${GLEW_LIBRARY}")
set(GLEW_INCLUDE_DIRS "${GLEW_INCLUDE_DIR}")
endif()

View File

@ -89,10 +89,6 @@
/* MP3 music */
#cmakedefine USE_MP3 1
/* Define to 1 if the userParam parameter to GLDEBUGPROCARB is const, as the
spec requires. */
#cmakedefine GLDEBUGPROCARB_USERPARAM_IS_CONST 1
/* Glib */
#cmakedefine WITH_GLIB 1

View File

@ -13,8 +13,6 @@
* for the above references.
*/
#include <GL/glew.h>
#include <C4Include.h>
#include <C4Console.h>
#include <C4Application.h>
@ -34,6 +32,8 @@
#include <StdFile.h>
#include <StdRegistry.h>
#include <epoxy/gl.h>
#import <Cocoa/Cocoa.h>
#import "C4AppDelegate.h"
#import "C4EditorWindowController.h"

View File

@ -12,8 +12,6 @@
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
#include <GL/glew.h>
#include <C4Include.h>
#include <C4Console.h>
@ -21,6 +19,8 @@
#include <C4PlayerList.h>
#include <C4Game.h>
#include <epoxy/gl.h>
#import <Cocoa/Cocoa.h>
#import <C4EditorWindowController.h>
#import <C4DrawGLMac.h>

View File

@ -80,13 +80,7 @@ namespace
}
}
#ifdef GLDEBUGPROCARB_USERPARAM_IS_CONST
#define USERPARAM_CONST const
#else
#define USERPARAM_CONST
#endif
void GLAPIENTRY OpenGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, USERPARAM_CONST void* userParam)
void GLAPIENTRY OpenGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam)
{
const char *msg_source = MsgSourceToStr(source);
const char *msg_type = MsgTypeToStr(type);
@ -100,8 +94,6 @@ namespace
}
}
#undef USERPARAM_CONST
CStdGL::CStdGL():
pMainCtx(0), CurrentVBO(0), NextVAOID(VAOIDs.end())
{
@ -276,10 +268,8 @@ bool CStdGL::PrepareSpriteShader(C4Shader& shader, const char* name, int ssc, C4
void CStdGL::ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char * label)
{
#ifdef GL_KHR_debug
if (glObjectLabel)
if (has_khr_debug)
glObjectLabel(identifier, name, length, label);
#endif
}
CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp)
@ -295,16 +285,20 @@ CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp)
pMainCtx = pCtx;
LogF(" gl: Create first %scontext...", Config.Graphics.DebugOpenGL ? "debug " : "");
}
bool success = pCtx->Init(pWindow, pApp);
if (Config.Graphics.DebugOpenGL && glDebugMessageCallbackARB)
if (!pCtx->Init(pWindow, pApp))
{
Log(" gl: failed to create context.");
delete pCtx;
return NULL;
}
has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug") || epoxy_gl_version() >= 43;
if (Config.Graphics.DebugOpenGL && (has_khr_debug || epoxy_has_gl_extension("GL_ARB_debug_output")))
{
if (first_ctx) Log(" gl: Setting OpenGLDebugProc callback");
glDebugMessageCallbackARB(&OpenGLDebugProc, nullptr);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
#ifdef GL_KHR_debug
if (GLEW_KHR_debug)
glDebugMessageCallback(&OpenGLDebugProc, nullptr);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
if (has_khr_debug)
glEnable(GL_DEBUG_OUTPUT);
#endif
}
// First context: Log some information about hardware/drivers
// Must log after context creation to get valid results
@ -317,7 +311,7 @@ CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp)
if (Config.Graphics.DebugOpenGL)
{
// Dump extension list
if (glGetStringi)
if (epoxy_is_desktop_gl() && epoxy_gl_version() >= 30)
{
GLint gl_extension_count = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &gl_extension_count);
@ -342,10 +336,6 @@ CStdGLCtx *CStdGL::CreateContext(C4Window * pWindow, C4AbstractApp *pApp)
}
}
}
if (!success)
{
delete pCtx; Error(" gl: Error creating secondary context!"); return NULL;
}
// creation selected the new context - switch back to previous context
RenderTarget = NULL;
pCurrCtx = NULL;

View File

@ -24,7 +24,7 @@
#include <C4windowswrapper.h>
#endif
#include <GL/glew.h>
#include <epoxy/gl.h>
#ifdef USE_COCOA
#import "ObjectiveCAssociated.h"
@ -206,6 +206,8 @@ protected:
std::set<unsigned int> VAOIDs;
std::set<unsigned int>::iterator NextVAOID;
bool has_khr_debug;
public:
// Create a new (unique) VAO ID. A VAO ID is a number that identifies
// a certain VAO across all OpenGL contexts. This indirection is needed

View File

@ -57,7 +57,7 @@ void CStdGLCtx::SelectCommon()
#ifdef USE_WGL
#include <GL/wglew.h>
#include <epoxy/wgl.h>
static PIXELFORMATDESCRIPTOR pfd; // desired pixel format
static HGLRC hrc = 0;
@ -70,7 +70,7 @@ static HGLRC hrc = 0;
static std::vector<int> EnumeratePixelFormats(HDC hdc)
{
std::vector<int> result;
if(!wglGetPixelFormatAttribivARB) return result;
if(!epoxy_has_wgl_extension(hdc, "WGL_ARB_pixel_format")) return result;
int n_formats;
int attributes = WGL_NUMBER_PIXEL_FORMATS_ARB;
@ -262,14 +262,6 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp)
try
{
tempContext.reset(new GLTempContext);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if(err != GLEW_OK)
{
// Problem: glewInit failed, something is seriously wrong.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
return false;
}
}
catch (const WinAPIError &e)
{
@ -318,7 +310,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp)
else
{
// create context
if (wglCreateContextAttribsARB)
if (epoxy_has_wgl_extension(hDC, "WGL_ARB_create_context"))
{
const int attribs[] = {
WGL_CONTEXT_FLAGS_ARB, Config.Graphics.DebugOpenGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
@ -348,17 +340,6 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp)
if (hrc)
{
Select();
// After selecting the new context, we have to reinitialize GLEW to
// update its function pointers - the driver may elect to expose
// different extensions depending on the context attributes
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK)
{
// Uh. This is a problem.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
return false;
}
this_context = contexts.insert(contexts.end(), this);
return true;
@ -370,6 +351,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp)
std::vector<int> CStdGLCtx::EnumerateMultiSamples() const
{
assert(hrc != 0);
std::vector<int> result;
std::vector<int> vec = EnumeratePixelFormats(hDC);
for(unsigned int i = 0; i < vec.size(); ++i)
@ -422,20 +404,10 @@ bool CStdGLCtx::PageFlip()
}
#elif defined(USE_GTK)
#include <GL/glxew.h>
#include <GL/glx.h>
#include <epoxy/glx.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
namespace {
void InitGLXPointers()
{
glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)(glXGetProcAddress((const GLubyte*)"glXGetVisualFromFBConfig"));
glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)(glXGetProcAddress((const GLubyte*)"glXChooseFBConfig"));
glXCreateNewContext = (PFNGLXCREATENEWCONTEXTPROC)(glXGetProcAddress((const GLubyte*)"glXCreateNewContext"));
}
}
CStdGLCtx::CStdGLCtx(): pWindow(0), ctx(0), this_context(contexts.end()) { }
void CStdGLCtx::Clear(bool multisample_change)
@ -468,22 +440,6 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
// store window
this->pWindow = pWindow;
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
InitGLXPointers();
if (!glXGetVisualFromFBConfig || !glXChooseFBConfig || !glXCreateNewContext)
{
return pGL->Error(" gl: Unable to retrieve GLX 1.4 entry points");
}
XVisualInfo *vis_info = glXGetVisualFromFBConfig(dpy, pWindow->Info);
// Create base context so we can initialize GLEW
GLXContext dummy_ctx = glXCreateContext(dpy, vis_info, 0, True);
XFree(vis_info);
glXMakeCurrent(dpy, pWindow->renderwnd, dummy_ctx);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK)
{
return pGL->Error((const char*)glewGetErrorString(err));
}
// Create Context with sharing (if this is the main context, our ctx will be 0, so no sharing)
const int attribs[] = {
@ -495,7 +451,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
};
GLXContext share_context = (pGL->pMainCtx != this) ? static_cast<GLXContext>(pGL->pMainCtx->ctx) : 0;
if (glXCreateContextAttribsARB)
if (epoxy_has_glx_extension(dpy, gdk_x11_get_default_screen(), "GLX_ARB_create_context"))
{
int (*oldErrorHandler) (Display *, XErrorEvent *) = XSetErrorHandler(GLXErrorHandler);
ctx = glXCreateContextAttribsARB(dpy, pWindow->Info, share_context, True, attribs);
@ -507,20 +463,9 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
ctx = glXCreateNewContext(dpy, pWindow->Info, GLX_RGBA_TYPE, share_context, True);
}
glXMakeCurrent(dpy, None, NULL);
glXDestroyContext(dpy, dummy_ctx);
// No luck?
if (!ctx) return pGL->Error(" gl: Unable to create context");
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
// init extensions
glewExperimental = GL_TRUE;
err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
this_context = contexts.insert(contexts.end(), this);
return true;
@ -600,14 +545,6 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
ctx = SDL_GL_CreateContext(pWindow->window);
// No luck at all?
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
// init extensions
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
this_context = contexts.insert(contexts.end(), this);
return true;

View File

@ -588,14 +588,6 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
setObjectiveCObject(ctx);
// No luck at all?
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
// init extensions
glewExperimental = GL_TRUE; // Init GL 3.0+ function pointers
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
// set the openglview's context
auto controller = pWindow->objectiveCObject<C4WindowController>();
if (controller && controller.openGLView)

View File

@ -22,11 +22,7 @@
#include "StdMeshMath.h"
#include "C4Surface.h"
#ifdef _WIN32
#include <C4windowswrapper.h>
#endif
#include <GL/glew.h>
#include <epoxy/gl.h>
// Shader version
const int C4Shader_Version = 150; // GLSL 1.50 / OpenGL 3.2

View File

@ -13,13 +13,13 @@
* for the above references.
*/
#include <GL/glew.h>
#include <C4Include.h>
#include <C4Console.h>
#include <C4Viewport.h>
#include <C4GraphicsSystem.h>
#include <epoxy/gl.h>
#import "C4AppDelegate+MainMenuActions.h"
#import "C4DrawGLMac.h"
#import "C4EditorWindowController.h"

View File

@ -16,14 +16,14 @@
// based on SDL implementation
#include <GL/glew.h>
#include <string>
#include <C4Include.h>
#include "C4App.h"
#include <C4Window.h>
#include <C4Draw.h>
#include "C4App.h"
#include <epoxy/gl.h>
#import <Cocoa/Cocoa.h>
#ifndef USE_CONSOLE

View File

@ -13,8 +13,6 @@
* for the above references.
*/
#include <GL/glew.h>
#include <C4Include.h>
#include <C4Application.h>
#include <C4Viewport.h>
@ -22,6 +20,8 @@
#include <C4FullScreen.h>
#include <C4Landscape.h>
#include <epoxy/gl.h>
#import "C4WindowController.h"
#import "C4DrawGLMac.h"
#import "C4EditorWindowController.h"

View File

@ -42,7 +42,7 @@
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <epoxy/glx.h>
// Some helper functions for choosing a proper visual

View File

@ -23,7 +23,7 @@ _otool="${OTOOL:-otool}"
_install_name_tool="${INSTALL_NAME_TOOL:-install_name_tool}"
# This regexp should match every lib we want to bundle.
_libs_to_bundle=".*?/lib(jpeg|GLEW|llvm|SDL|SDL_mixer|freetype|ogg|vorbis|vorbisfile|z\.|png[0-9]*|alut)\.[^ ]+\.dylib"
_libs_to_bundle=".*?/lib(jpeg|epoxy|llvm|SDL|SDL_mixer|freetype|ogg|vorbis|vorbisfile|z\.|png[0-9]*|alut)\.[^ ]+\.dylib"
if [ -n "${TARGET_BUILD_DIR}" ]; then
cd "${TARGET_BUILD_DIR}"