UltimateZoneBuilder/Source/Native/OpenGLContext.cpp

625 lines
20 KiB
C++
Raw Normal View History

2019-08-10 00:32:08 +00:00
#include "Precomp.h"
#include "OpenGLContext.h"
#include <CommCtrl.h>
#include <stdexcept>
2019-08-10 00:32:08 +00:00
#ifdef WIN32
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#define ERROR_INVALID_VERSION_ARB 0x2095
#define WGL_NUMBER_CL_PIXEL_FORMATS 0x2000
#define WGL_DRAW_TO_WINDOW 0x2001
#define WGL_DRAW_TO_BITMAP 0x2002
#define WGL_ACCELERATION 0x2003
#define WGL_NEED_PALETTE 0x2004
#define WGL_NEED_SYSTEM_PALETTE 0x2005
#define WGL_SWAP_LAYER_BUFFERS 0x2006
#define WGL_SWAP_METHOD 0x2007
#define WGL_NUMBER_OVERLAYS 0x2008
#define WGL_NUMBER_UNDERLAYS 0x2009
#define WGL_TRANSPARENT 0x200A
#define WGL_TRANSPARENT_VALUE 0x200B
#define WGL_SHARE_DEPTH 0x200C
#define WGL_SHARE_STENCIL 0x200D
#define WGL_SHARE_ACCUM 0x200E
#define WGL_SUPPORT_GDI 0x200F
#define WGL_SUPPORT_OPENGL 0x2010
#define WGL_DOUBLE_BUFFER 0x2011
#define WGL_STEREO 0x2012
#define WGL_PIXEL_TYPE 0x2013
#define WGL_COLOR_BITS 0x2014
#define WGL_RED_BITS 0x2015
#define WGL_RED_SHIFT 0x2016
#define WGL_GREEN_BITS 0x2017
#define WGL_GREEN_SHIFT 0x2018
#define WGL_BLUE_BITS 0x2019
#define WGL_BLUE_SHIFT 0x201A
#define WGL_ALPHA_BITS 0x201B
#define WGL_ALPHA_SHIFT 0x201C
#define WGL_ACCUM_BITS 0x201D
#define WGL_ACCUM_RED_BITS 0x201E
#define WGL_ACCUM_GREEN_BITS 0x201F
#define WGL_ACCUM_BLUE_BITS 0x2020
#define WGL_ACCUM_ALPHA_BITS 0x2021
#define WGL_DEPTH_BITS 0x2022
#define WGL_STENCIL_BITS 0x2023
#define WGL_AUX_BUFFERS 0x2024
#define WGL_NO_ACCELERATION 0x2025
#define WGL_GENERIC_ACCELERATION 0x2026
#define WGL_FULL_ACCELERATION 0x2027
#define WGL_SWAP_EXCHANGE 0x2028
#define WGL_SWAP_COPY 0x2029
#define WGL_SWAP_UNDEFINED 0x202A
#define WGL_TYPE_RGBA 0x202B
#define WGL_TYPE_COLORINDEX 0x202C
#define WGL_SAMPLE_BUFFERS 0x2041
#define WGL_SAMPLES 0x2042
/////////////////////////////////////////////////////////////////////////////
class OpenGLLoadFunctions
{
public:
OpenGLLoadFunctions() { ogl_LoadFunctions(); }
};
/////////////////////////////////////////////////////////////////////////////
OpenGLContext::OpenGLContext(void* windowptr) : window((HWND)windowptr)
2019-08-10 00:32:08 +00:00
{
dc = GetDC(window);
OpenGLCreationHelper helper(window);
context = helper.CreateContext(dc, 3, 2);
if (context)
{
2019-08-22 13:46:24 +00:00
MakeCurrent();
2019-08-10 00:32:08 +00:00
static OpenGLLoadFunctions loadFunctions;
2019-08-22 13:46:24 +00:00
ClearCurrent();
2019-08-10 00:32:08 +00:00
}
}
OpenGLContext::~OpenGLContext()
{
if (context)
wglDeleteContext(context);
if (dc)
ReleaseDC(window, dc);
}
2019-08-22 13:46:24 +00:00
void OpenGLContext::MakeCurrent()
2019-08-10 00:32:08 +00:00
{
2019-08-22 13:46:24 +00:00
wglMakeCurrent(dc, context);
2019-08-10 00:32:08 +00:00
}
2019-08-22 13:46:24 +00:00
void OpenGLContext::ClearCurrent()
2019-08-10 00:32:08 +00:00
{
2019-08-22 13:46:24 +00:00
wglMakeCurrent(0, 0);
2019-08-10 00:32:08 +00:00
}
void OpenGLContext::SwapBuffers()
{
::SwapBuffers(dc);
}
int OpenGLContext::GetWidth() const
{
RECT box = { 0 };
GetClientRect(window, &box);
return box.right - box.left;
}
int OpenGLContext::GetHeight() const
{
RECT box = { 0 };
GetClientRect(window, &box);
return box.bottom - box.top;
}
2019-08-10 00:32:08 +00:00
/////////////////////////////////////////////////////////////////////////////
OpenGLCreationHelper::OpenGLCreationHelper(HWND window) : window(window)
{
WINDOWINFO window_info;
memset(&window_info, 0, sizeof(WINDOWINFO));
window_info.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(window, &window_info);
query_window = CreateWindowEx(
0,
WC_STATIC,
TEXT(""),
WS_CHILD,
window_info.rcWindow.left,
window_info.rcWindow.top,
window_info.rcWindow.right - window_info.rcWindow.left,
window_info.rcWindow.bottom - window_info.rcWindow.top,
window, 0, GetModuleHandle(0), 0);
if (query_window == 0)
return;
query_dc = GetDC(query_window);
if (query_dc == 0)
{
DestroyWindow(query_window);
query_window = 0;
return;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
int pixelformat = ChoosePixelFormat(query_dc, &pfd);
SetPixelFormat(query_dc, pixelformat, &pfd);
query_context = wglCreateContext(query_dc);
if (query_context == 0)
{
DeleteDC(query_dc);
DestroyWindow(query_window);
query_dc = 0;
query_window = 0;
}
}
OpenGLCreationHelper::~OpenGLCreationHelper()
{
wglDeleteContext(query_context);
DeleteDC(query_dc);
DestroyWindow(query_window);
}
HGLRC OpenGLCreationHelper::CreateContext(HDC hdc, int major_version, int minor_version, HGLRC share_context)
{
if (query_context == 0)
return 0;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
2019-08-10 00:32:08 +00:00
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cAlphaBits = 8;
2019-08-10 00:32:08 +00:00
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
2019-08-10 00:32:08 +00:00
int pixelformat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, pixelformat, &pfd);
wglMakeCurrent(query_dc, query_context);
ptr_wglCreateContextAttribsARB wglCreateContextAttribsARB = (ptr_wglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB");
HGLRC opengl3_context = 0;
if (wglCreateContextAttribsARB)
{
std::vector<int> int_attributes;
int_attributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
int_attributes.push_back(major_version);
int_attributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
int_attributes.push_back(minor_version);
int_attributes.push_back(0x2094); // WGL_CONTEXT_FLAGS_ARB
int_attributes.push_back(0x2); // WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
int_attributes.push_back(0x9126); // WGL_CONTEXT_PROFILE_MASK_ARB
int_attributes.push_back(0x1); // WGL_CONTEXT_CORE_PROFILE_BIT_ARB
int_attributes.push_back(0);
opengl3_context = wglCreateContextAttribsARB(hdc, share_context, int_attributes.data());
}
wglMakeCurrent(0, 0);
return opengl3_context;
}
#else
#include <cstdio>
#define GL_USE_DLOPEN // Using dlopen for linux by default
#ifdef GL_USE_DLOPEN
#define GL_OPENGL_LIBRARY "libGL.so.1"
#include <dlfcn.h>
#endif
#ifdef GL_USE_DLOPEN
#define GL_LOAD_GLFUNC(x) dlsym(opengl_lib_handle, # x)
#else
#define GL_LOAD_GLFUNC(x) &x
#endif
OpenGLContext::OpenGLContext(void* display, void* window) : disp((::Display*)display), window((::Window)window)
{
try
{
CreateContext();
}
catch (const std::exception& e)
{
// to do: maybe provide a way to query what the creation error was
}
}
OpenGLContext::~OpenGLContext()
{
if (opengl_visual_info)
{
XFree(opengl_visual_info);
opengl_visual_info = nullptr;
}
if (opengl_context)
{
if (glx.glXGetCurrentContext() == opengl_context)
OpenGL::set_active(nullptr);
if (disp)
glx.glXDestroyContext(disp, opengl_context);
opengl_context = nullptr;
}
}
2019-08-22 13:46:24 +00:00
void OpenGLContext::MakeCurrent()
{
2019-08-22 13:46:24 +00:00
glx.glXMakeCurrent(disp, window, opengl_context);
}
2019-08-22 13:46:24 +00:00
void OpenGLContext::ClearCurrent()
{
2019-08-22 13:46:24 +00:00
glx.glXMakeCurrent(0, 0, opengl_context);
}
void OpenGLContext::SwapBuffers()
{
glx.glXSwapBuffers(disp, window);
}
int OpenGLContext::GetWidth() const
{
::Window root_window;
int x, y;
unsigned int width, height, border_width, border_height, depth;
Status result = XGetGeometry(disp, window, &root_window, &x, &y, &width, &height, &border_width, &border_height, &depth);
return (result != 0) ? width: 0;
}
int OpenGLContext::GetHeight() const
{
::Window root_window;
int x, y;
unsigned int width, height, border_width, border_height, depth;
Status result = XGetGeometry(disp, window, &root_window, &x, &y, &width, &height, &border_width, &border_height, &depth);
return (result != 0) ? height : 0;
}
ProcAddress* OpenGLContext::get_proc_address(const char *function_name) const
{
if (glx.glXGetProcAddressARB)
return glx.glXGetProcAddressARB((GLubyte*)function_name);
else if (glx.glXGetProcAddress)
return glx.glXGetProcAddress((GLubyte*)function_name);
else
return nullptr;
}
void OpenGLContext::CreateContext()
{
#ifdef GL_USE_DLOPEN
opengl_lib_handle = dlopen(GL_OPENGL_LIBRARY, RTLD_NOW | RTLD_GLOBAL);
if (!opengl_lib_handle)
throw std::runtime_error(std::string("Cannot open opengl library: ") + GL_OPENGL_LIBRARY);
#endif
glx.glXChooseVisual = (GL_GLXFunctions::ptr_glXChooseVisual) GL_LOAD_GLFUNC(glXChooseVisual);
glx.glXCopyContext = (GL_GLXFunctions::ptr_glXCopyContext) GL_LOAD_GLFUNC(glXCopyContext);
glx.glXCreateContext = (GL_GLXFunctions::ptr_glXCreateContext) GL_LOAD_GLFUNC(glXCreateContext);
glx.glXCreateGLXPixmap = (GL_GLXFunctions::ptr_glXCreateGLXPixmap) GL_LOAD_GLFUNC(glXCreateGLXPixmap);
glx.glXDestroyContext = (GL_GLXFunctions::ptr_glXDestroyContext) GL_LOAD_GLFUNC(glXDestroyContext);
glx.glXDestroyGLXPixmap = (GL_GLXFunctions::ptr_glXDestroyGLXPixmap) GL_LOAD_GLFUNC(glXDestroyGLXPixmap);
glx.glXGetConfig = (GL_GLXFunctions::ptr_glXGetConfig) GL_LOAD_GLFUNC(glXGetConfig);
glx.glXGetCurrentContext = (GL_GLXFunctions::ptr_glXGetCurrentContext) GL_LOAD_GLFUNC(glXGetCurrentContext);
glx.glXGetCurrentDrawable = (GL_GLXFunctions::ptr_glXGetCurrentDrawable) GL_LOAD_GLFUNC(glXGetCurrentDrawable);
glx.glXIsDirect = (GL_GLXFunctions::ptr_glXIsDirect) GL_LOAD_GLFUNC(glXIsDirect);
glx.glXMakeCurrent = (GL_GLXFunctions::ptr_glXMakeCurrent) GL_LOAD_GLFUNC(glXMakeCurrent);
glx.glXQueryExtension = (GL_GLXFunctions::ptr_glXQueryExtension) GL_LOAD_GLFUNC(glXQueryExtension);
glx.glXQueryVersion = (GL_GLXFunctions::ptr_glXQueryVersion) GL_LOAD_GLFUNC(glXQueryVersion);
glx.glXSwapBuffers = (GL_GLXFunctions::ptr_glXSwapBuffers) GL_LOAD_GLFUNC(glXSwapBuffers);
glx.glXUseXFont = (GL_GLXFunctions::ptr_glXUseXFont) GL_LOAD_GLFUNC(glXUseXFont);
glx.glXWaitGL = (GL_GLXFunctions::ptr_glXWaitGL) GL_LOAD_GLFUNC(glXWaitGL);
glx.glXWaitX = (GL_GLXFunctions::ptr_glXWaitX) GL_LOAD_GLFUNC(glXWaitX);
glx.glXGetClientString = (GL_GLXFunctions::ptr_glXGetClientString) GL_LOAD_GLFUNC(glXGetClientString);
glx.glXQueryServerString = (GL_GLXFunctions::ptr_glXQueryServerString) GL_LOAD_GLFUNC(glXQueryServerString);
glx.glXQueryExtensionsString = (GL_GLXFunctions::ptr_glXQueryExtensionsString) GL_LOAD_GLFUNC(glXQueryExtensionsString);
glx.glXGetCurrentDisplay = (GL_GLXFunctions::ptr_glXGetCurrentDisplay) GL_LOAD_GLFUNC(glXGetCurrentDisplay);
glx.glXChooseFBConfig = (GL_GLXFunctions::ptr_glXChooseFBConfig) GL_LOAD_GLFUNC(glXChooseFBConfig);
glx.glXCreateNewContext = (GL_GLXFunctions::ptr_glXCreateNewContext) GL_LOAD_GLFUNC(glXCreateNewContext);
glx.glXCreatePbuffer = (GL_GLXFunctions::ptr_glXCreatePbuffer) GL_LOAD_GLFUNC(glXCreatePbuffer);
glx.glXCreatePixmap = (GL_GLXFunctions::ptr_glXCreatePixmap) GL_LOAD_GLFUNC(glXCreatePixmap);
glx.glXCreateWindow = (GL_GLXFunctions::ptr_glXCreateWindow) GL_LOAD_GLFUNC(glXCreateWindow);
glx.glXDestroyPbuffer = (GL_GLXFunctions::ptr_glXDestroyPbuffer) GL_LOAD_GLFUNC(glXDestroyPbuffer);
glx.glXDestroyPixmap = (GL_GLXFunctions::ptr_glXDestroyPixmap) GL_LOAD_GLFUNC(glXDestroyPixmap);
glx.glXDestroyWindow = (GL_GLXFunctions::ptr_glXDestroyWindow) GL_LOAD_GLFUNC(glXDestroyWindow);
glx.glXGetCurrentReadDrawable = (GL_GLXFunctions::ptr_glXGetCurrentReadDrawable) GL_LOAD_GLFUNC(glXGetCurrentReadDrawable);
glx.glXGetFBConfigAttrib = (GL_GLXFunctions::ptr_glXGetFBConfigAttrib) GL_LOAD_GLFUNC(glXGetFBConfigAttrib);
glx.glXGetFBConfigs = (GL_GLXFunctions::ptr_glXGetFBConfigs) GL_LOAD_GLFUNC(glXGetFBConfigs);
glx.glXGetSelectedEvent = (GL_GLXFunctions::ptr_glXGetSelectedEvent) GL_LOAD_GLFUNC(glXGetSelectedEvent);
glx.glXGetVisualFromFBConfig = (GL_GLXFunctions::ptr_glXGetVisualFromFBConfig) GL_LOAD_GLFUNC(glXGetVisualFromFBConfig);
glx.glXMakeContextCurrent = (GL_GLXFunctions::ptr_glXMakeContextCurrent) GL_LOAD_GLFUNC(glXMakeContextCurrent);
glx.glXQueryContext = (GL_GLXFunctions::ptr_glXQueryContext) GL_LOAD_GLFUNC(glXQueryContext);
glx.glXQueryDrawable = (GL_GLXFunctions::ptr_glXQueryDrawable) GL_LOAD_GLFUNC(glXQueryDrawable);
glx.glXSelectEvent = (GL_GLXFunctions::ptr_glXSelectEvent) GL_LOAD_GLFUNC(glXSelectEvent);
glx.glXGetProcAddressARB = (GL_GLXFunctions::ptr_glXGetProcAddressARB) GL_LOAD_GLFUNC(glXGetProcAddressARB);
glx.glXGetProcAddress = (GL_GLXFunctions::ptr_glXGetProcAddress) GL_LOAD_GLFUNC(glXGetProcAddress);
if ((glx.glXDestroyContext == nullptr) ||
(glx.glXMakeCurrent == nullptr) ||
(glx.glXGetCurrentContext == nullptr) ||
(glx.glXChooseVisual == nullptr) ||
(glx.glXIsDirect == nullptr) ||
(glx.glXGetConfig == nullptr) ||
(glx.glXQueryExtensionsString == nullptr) ||
(glx.glXQueryVersion == nullptr) ||
(glx.glXGetVisualFromFBConfig == nullptr) ||
(glx.glXCreateNewContext == nullptr) ||
(glx.glXCreateContext == nullptr))
{
throw std::runtime_error("Cannot obtain required OpenGL GLX functions");
}
if ((glx.glXGetProcAddressARB == nullptr) && (glx.glXGetProcAddress == nullptr))
{
throw std::runtime_error("Cannot obtain required OpenGL GLX functions");
}
// FBConfigs were added in GLX version 1.3.
int glx_major, glx_minor;
if (!glx.glXQueryVersion(disp, &glx_major, &glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1))
throw std::runtime_error("GLX 1.3 or better is required");
create_glx_1_3(disp);
//if (!glx.glXIsDirect(disp, opengl_context))
// printf("No hardware acceleration available. I hope you got a really fast machine.\n");
}
void OpenGLContext::create_glx_1_3(::Display* disp)
{
if (glx.glXChooseFBConfig == nullptr)
throw std::runtime_error("Cannot find the glXChooseFBConfig function");
// Setup OpenGL:
int gl_attribs_single[] =
{
GLX_X_RENDERABLE, True,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DEPTH_SIZE, 16,
GLX_STENCIL_SIZE, 8,
GLX_BUFFER_SIZE, 24,
None
};
std::vector<int> gl_attribs;
gl_attribs.reserve(64);
gl_attribs.push_back(GLX_X_RENDERABLE);
gl_attribs.push_back(True);
gl_attribs.push_back(GLX_DRAWABLE_TYPE);
gl_attribs.push_back(GLX_WINDOW_BIT);
gl_attribs.push_back(GLX_RENDER_TYPE);
gl_attribs.push_back(GLX_RGBA_BIT);
gl_attribs.push_back(GLX_X_VISUAL_TYPE);
gl_attribs.push_back(GLX_TRUE_COLOR);
gl_attribs.push_back(GLX_RED_SIZE);
gl_attribs.push_back(8);
gl_attribs.push_back(GLX_GREEN_SIZE);
gl_attribs.push_back(8);
gl_attribs.push_back(GLX_BLUE_SIZE);
gl_attribs.push_back(8);
gl_attribs.push_back(GLX_ALPHA_SIZE);
gl_attribs.push_back(8);
gl_attribs.push_back(GLX_DEPTH_SIZE);
gl_attribs.push_back(24);
gl_attribs.push_back(GLX_STENCIL_SIZE);
gl_attribs.push_back(8);
gl_attribs.push_back(GLX_DOUBLEBUFFER);
gl_attribs.push_back(True);
gl_attribs.push_back(GLX_STEREO);
gl_attribs.push_back(False);
gl_attribs.push_back(None);
// get an appropriate visual
int fb_count;
GLXFBConfig* fbc = glx.glXChooseFBConfig(disp, DefaultScreen(disp), &gl_attribs[0], &fb_count);
if (!fbc)
{
printf("Requested visual not supported by your OpenGL implementation. Falling back on singlebuffered Visual!\n");
fbc = glx.glXChooseFBConfig(disp, DefaultScreen(disp), gl_attribs_single, &fb_count);
if (!fbc)
throw std::runtime_error(" glxChooseFBConfig failed");
fbconfig = fbc[0];
}
else
{
if (!glx.glXGetFBConfigAttrib)
throw std::runtime_error("Cannot find function glXGetFBConfigAttrib");
int required_samples = 1; // desc.multisampling();
int desired_config = 0;
int max_sample_buffers = 0;
int max_samples = 0;
// Find the best fitting multisampling option
for (int i = 0; i < fb_count; i++)
{
int samp_buf, samples;
glx.glXGetFBConfigAttrib(disp, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
glx.glXGetFBConfigAttrib(disp, fbc[i], GLX_SAMPLES, &samples);
// Samples are most important, because they are variable
if (max_samples < required_samples)
{
if (samples > max_samples)
{
max_samples = samples;
desired_config = i;
}
}
// Use the maximum sample buffer
if (max_samples == samples) // Only check if the sample is valid
{
if (max_sample_buffers < samp_buf)
{
max_sample_buffers = samp_buf;
desired_config = i;
}
}
}
fbconfig = fbc[desired_config];
}
XFree(fbc);
if (opengl_visual_info) XFree(opengl_visual_info);
opengl_visual_info = glx.glXGetVisualFromFBConfig(disp, fbconfig);
if (opengl_visual_info == nullptr)
{
throw std::runtime_error("glXGetVisualFromFBConfig failed");
}
// create a GLX context
opengl_context = create_context_glx_1_3(nullptr);
}
bool OpenGLContext::is_glx_extension_supported(const char* ext_name)
{
const char* ext_string = glx.glXQueryExtensionsString(disp, opengl_visual_info->screen);
if (ext_string)
{
const char* start;
const char* where, * terminator;
// Extension names should not have spaces.
where = strchr(ext_name, ' ');
if (where || *ext_name == '\0')
return false;
int ext_len = strlen(ext_name);
// It takes a bit of care to be fool-proof about parsing the OpenGL extensions string. Don't be fooled by sub-strings, etc.
for (start = ext_string; ; )
{
where = strstr(start, ext_name);
if (!where)
break;
terminator = where + ext_len;
if (where == start || *(where - 1) == ' ')
if (*terminator == ' ' || *terminator == '\0')
return true;
start = terminator;
}
}
return false;
}
static bool cl_ctxErrorOccurred = false;
static int cl_ctxErrorHandler(::Display* dpy, XErrorEvent* ev)
{
cl_ctxErrorOccurred = true;
return 0;
}
GLXContext OpenGLContext::create_context_glx_1_3(GLXContext shared_context)
{
GLXContext context;
context = glx.glXCreateNewContext(disp, fbconfig, GLX_RGBA_TYPE, shared_context, True);
if (context == nullptr)
throw std::runtime_error("glXCreateContext failed");
ptr_glXCreateContextAttribs glXCreateContextAttribs = nullptr;
if (is_glx_extension_supported("GLX_ARB_create_context"))
{
if (glx.glXGetProcAddressARB)
glXCreateContextAttribs = (ptr_glXCreateContextAttribs)glx.glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
if (glx.glXGetProcAddress)
glXCreateContextAttribs = (ptr_glXCreateContextAttribs)glx.glXGetProcAddress((GLubyte*) "glXCreateContextAttribsARB");
}
if (glXCreateContextAttribs)
{
// Install an X error handler so the application won't exit if GL 3.0 context allocation fails.
//
// Note this error handler is global. All display connections in all threads
// of a process use the same error handler, so be sure to guard against other
// threads issuing X commands while this code is running.
int (*oldHandler)(::Display*, XErrorEvent*) = XSetErrorHandler(&cl_ctxErrorHandler);
std::vector<int> int_attributes;
int_attributes.push_back(0x2091); // GLX_CONTEXT_MAJOR_VERSION_ARB
int_attributes.push_back(major_version);
int_attributes.push_back(0x2092); // GLX_CONTEXT_MINOR_VERSION_ARB
int_attributes.push_back(minor_version);
int_attributes.push_back(0x2094); // GLX_CONTEXT_FLAGS_ARB
int_attributes.push_back(0x2); // GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
int_attributes.push_back(0x9126); // GLX_CONTEXT_PROFILE_MASK_ARB
int_attributes.push_back(0x1); // GLX_CONTEXT_CORE_PROFILE_BIT_ARB
int_attributes.push_back(None);
cl_ctxErrorOccurred = false;
GLXContext context_gl3 = glXCreateContextAttribs(disp, fbconfig, shared_context, True, &int_attributes[0]);
if (cl_ctxErrorOccurred)
{
if (context_gl3)
{
glx.glXDestroyContext(disp, context_gl3);
context_gl3 = nullptr;
}
}
// Restore the original error handler
XSetErrorHandler(oldHandler);
if (context_gl3)
{
glx.glXDestroyContext(disp, context);
context = context_gl3;
}
}
return context;
}
#endif