3#include "GLFuncPointers.h"
5#include "../IGraphicsDevice.h"
7#include "Foundation/Logging/Logger.h"
8#include "Foundation/Platform/WindowData.h"
15PFNGLXGETPROCADDRESSPROC _glXGetProcAddress =
nullptr;
16GLXFBConfig Cogs::GLContext::fbConfig =
nullptr;
22 bool has_GLX_EXT_swap_control =
false;
23 bool has_GLX_EXT_swap_control_tear =
false;
31 void* libX11 =
nullptr;
32 static const char* libX11Names[] = {
36 Display*(*_XOpenDisplay)(
const char*) =
nullptr;
37 Colormap (*_XCreateColormap)(Display*, Window, Visual*, int) =
nullptr;
38 Window (*_XCreateWindow)(Display*, Window, int, int,
unsigned int,
unsigned int,
unsigned int, int,
unsigned int, Visual*,
unsigned long, XSetWindowAttributes*) =
nullptr;
39 int (*_XDestroyWindow)(Display* display, ::Window w);
40 int (*_XFreeColormap)(Display*, Colormap) =
nullptr;
41 int (*_XFree)(
void*) =
nullptr;
43 LibFunc libX11Funcs[] = {
44 { (
void**)&_XOpenDisplay,
"XOpenDisplay" },
45 { (
void**)&_XCreateColormap,
"XCreateColormap" },
46 { (
void**)&_XCreateWindow,
"XCreateWindow" },
47 { (
void**)&_XDestroyWindow,
"XDestroyWindow" },
48 { (
void**)&_XFreeColormap,
"XFreeColormap" },
49 { (
void**)&_XFree,
"XFree" }
54 void* libGLX =
nullptr;
55 static const char* libGLXNames[] = {
60 bool (*_glXQueryVersion)(Display* dpy,
int* maj,
int* min) =
nullptr;
61 const char* (*_glXQueryExtensionsString)( Display *dpy,
int screen );
62 GLXContext (*_glXCreateContext)(Display *, XVisualInfo*, GLXContext, bool) =
nullptr;
63 void (*_glXDestroyContext)(Display *, GLXContext);
64 bool (*_glXMakeCurrent)(Display *, GLXDrawable, GLXContext);
65 void (*_glXSwapBuffers)(Display *, GLXDrawable);
66 bool (*_glXIsDirect)(Display*, GLXContext);
67 PFNGLXCHOOSEFBCONFIGPROC _glXChooseFBConfig =
nullptr;
68 PFNGLXGETFBCONFIGATTRIBPROC _glXGetFBConfigAttrib =
nullptr;
69 PFNGLXGETVISUALFROMFBCONFIGPROC _glXGetVisualFromFBConfig =
nullptr;
70 PFNGLXQUERYRENDERERINTEGERMESAPROC _glXQueryRendererIntegerMESA =
nullptr;
71 PFNGLXCREATECONTEXTATTRIBSARBPROC _glXCreateContextAttribsARB =
nullptr;
72 PFNGLXSWAPINTERVALEXTPROC _glXSwapIntervalEXT =
nullptr;
74 LibFunc libGLXFuncs[] = {
75 { (
void**)&_glXQueryVersion,
"glXQueryVersion" },
76 { (
void**)&_glXQueryExtensionsString,
"glXQueryExtensionsString" },
77 { (
void**)&_glXCreateContext,
"glXCreateContext" },
78 { (
void**)&_glXDestroyContext,
"glXDestroyContext" },
79 { (
void**)&_glXMakeCurrent,
"glXMakeCurrent" },
80 { (
void**)&_glXSwapBuffers,
"glXSwapBuffers" },
81 { (
void**)&_glXChooseFBConfig,
"glXChooseFBConfig" },
82 { (
void**)&_glXGetProcAddress,
"glXGetProcAddress" },
83 { (
void**)&_glXGetFBConfigAttrib,
"glXGetFBConfigAttrib" },
84 { (
void**)&_glXGetVisualFromFBConfig,
"glXGetVisualFromFBConfig" },
85 { (
void**)&_glXQueryRendererIntegerMESA,
"glXQueryRendererIntegerMESA" },
86 { (
void**)&_glXCreateContextAttribsARB,
"glXCreateContextAttribsARB" },
87 { (
void**)&_glXIsDirect,
"glXIsDirect" },
88 { (
void**)&_glXSwapIntervalEXT,
"glXSwapIntervalEXT" },
92 void* openLib(
const std::span<const char*>& libNameCandidates)
94 for (
const char* libName : libNameCandidates) {
95 void* lib = dlopen(libName, RTLD_LAZY | RTLD_LOCAL);
96 if (lib) {
return lib; }
101 static bool initialized =
false;
109 if (libX11 ==
nullptr) {
110 libX11 = openLib(libX11Names);
111 if (libX11 ==
nullptr) {
112 LOG_FATAL(logger,
"Failed to load libX11");
117 for (
const LibFunc& libFunc : libX11Funcs) {
118 *libFunc.ptr = dlsym(libX11, libFunc.name);
119 if (*libFunc.ptr ==
nullptr) {
120 LOG_FATAL(logger,
"Failed to lookup libX11 function %s", libFunc.name);
123 LOG_TRACE(logger,
"Looked up %s", libFunc.name);
126 if (libGLX ==
nullptr) {
127 libGLX = openLib(libGLXNames);
128 if (libGLX ==
nullptr) {
129 LOG_FATAL(logger,
"Failed to load libGLX");
134 if(_glXGetProcAddress ==
nullptr) {
135 _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)dlsym(libGLX,
"glXGetProcAddress");
136 if(_glXGetProcAddress ==
nullptr) {
137 LOG_FATAL(logger,
"Failed to lookup libGLX function glXGetProcAddress");
142 for (
const LibFunc& libFunc : libGLXFuncs) {
143 *libFunc.ptr = (
void*)_glXGetProcAddress((
const GLubyte*)libFunc.name);
144 if (*libFunc.ptr ==
nullptr) {
145 LOG_FATAL(logger,
"Failed to lookup libGLX function %s", libFunc.name);
148 LOG_TRACE(logger,
"Looked up %s", libFunc.name);
155 bool finalizeContext(Cogs::GLContextBase::Platform platform,
bool debug,
bool sRGB)
158 Cogs::setUpGLDebugging(
nullptr, platform);
161 glEnable(GL_FRAMEBUFFER_SRGB_EXT);
163 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
169bool Cogs::GLContext::create(NativeDisplay display, WindowData* windowData, GLContext* shareContext,
const GraphicsDeviceSettings* settings, Platform desiredPlatform,
bool debug)
175 assert(desiredPlatform == Platform::GL &&
"ES3 not yet implemented");
177 if(shareContext && shareContext->dpy) {
178 dpy = shareContext->dpy;
184 dpy = _XOpenDisplay(
nullptr);
186 LOG_FATAL(logger,
"Failed to open display");
193 if (!_glXQueryVersion(dpy, &glxMajor, &glxMinor)) {
194 LOG_FATAL(logger,
"glXQueryVersion failed");
197 LOG_DEBUG(logger,
"Got GLX version %d.%d", glxMajor, glxMinor);
198 if ((glxMajor < 1) || ((glxMajor == 1) && (glxMinor < 3))) {
199 LOG_FATAL(logger,
"GLX version is less than the 1.3 minimum version");
203 int screen = DefaultScreen(dpy);
204 const char* glxExtensions = _glXQueryExtensionsString(dpy, screen);
205 if (strstr(glxExtensions,
"GLX_EXT_swap_control") !=
nullptr) {
206 LOG_DEBUG(logger,
"GLX_EXT_swap_control present");
207 has_GLX_EXT_swap_control =
true;
209 if (strstr(glxExtensions,
"GLX_EXT_swap_control_tear") !=
nullptr) {
210 LOG_DEBUG(logger,
"GLX_EXT_swap_control_tear present");
211 has_GLX_EXT_swap_control_tear =
true;
214 if (strstr(glxExtensions,
"GLX_EXT_framebuffer_sRGB") !=
nullptr) {
215 LOG_DEBUG(logger,
"GLX_EXT_framebuffer_sRGB present");
219 GLXFBConfig bestFbc = getFBConfig(dpy, settings ? settings->numSamples : 0);
220 XVisualInfo* visualInfo = _glXGetVisualFromFBConfig(dpy, bestFbc);
223 win = windowData->windowHandle;
226 LOG_DEBUG(logger,
"Creating headless dummy window");
229 XSetWindowAttributes swa = {};
230 swa.event_mask = StructureNotifyMask;
231 swa.colormap = _XCreateColormap(dpy, RootWindow(dpy, screen), visualInfo->visual, AllocNone);
233 win = _XCreateWindow(dpy,
234 RootWindow(dpy, screen),
239 CWBorderPixel | CWColormap | CWEventMask,
242 LOG_ERROR(logger,
"Error creating offscreen window handle");
247 if(strstr(glxExtensions,
"GLX_ARB_create_context") !=
nullptr) {
248 LOG_DEBUG(logger,
"GLX_ARB_create_context present, using glXCreateContextAttribsARB");
250 GLuint version[2] = { 3, 0};
251 if(strstr(glxExtensions,
"GLX_MESA_query_renderer") !=
nullptr) {
252 if(_glXQueryRendererIntegerMESA(dpy, screen, 0, GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA, version)) {
253 LOG_DEBUG(logger,
"GLX renderer version=%u.%u", version[0], version[1]);
257 GLint contextFlags = debug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0;
258 const GLint attributes[] = {
259 GLX_CONTEXT_MAJOR_VERSION_ARB, (GLint)version[0],
260 GLX_CONTEXT_MINOR_VERSION_ARB, (GLint)version[1],
261 GLX_CONTEXT_FLAGS_ARB, contextFlags,
264 glc = _glXCreateContextAttribsARB(dpy,
266 shareContext ? shareContext->glc :
nullptr,
271 LOG_DEBUG(logger,
"GLX_ARB_create_context missing, using glXCreateContext");
272 glc = _glXCreateContext(dpy,
274 shareContext ? shareContext->glc :
nullptr,
278 if (glc ==
nullptr) {
279 LOG_ERROR(logger,
"Failed to create context");
283 if (_glXIsDirect(dpy, glc)) {
284 LOG_DEBUG(logger,
"Created direct GLX context");
287 LOG_DEBUG(logger,
"Created indirect GLX context");
290 if(!_glXMakeCurrent(dpy, win, glc)) {
291 LOG_ERROR(logger,
"Failed to make context current");
294 finalizeContext(platform, debug, sRGB);
298bool Cogs::GLContext::makeCurrent()
300 return _glXMakeCurrent(dpy, win, glc);
303void Cogs::GLContext::swapBuffers(uint32_t syncInterval, uint32_t presentFlags)
305 if ((presentFlags & PresentFlags::NoSwap) == 0) {
306 if (has_GLX_EXT_swap_control || has_GLX_EXT_swap_control_tear) {
307 _glXSwapIntervalEXT(dpy, win, syncInterval != 0 ? 1 : 0);
309 _glXSwapBuffers(dpy, win);
313void Cogs::GLContext::destroy()
316 _glXDestroyContext(dpy, glc);
319 if(win && ownWindow) {
320 _XDestroyWindow(dpy, win);
325GLXFBConfig Cogs::GLContext::getFBConfig(NativeDisplay display,
int requestedSampleCount) {
334 std::vector<GLint> attributes = {
335 GLX_X_RENDERABLE,
true,
336 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
337 GLX_RENDER_TYPE, GLX_RGBA_BIT,
338 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
345 GLX_DOUBLEBUFFER,
true,
349 GLXFBConfig* fbConfigs =
nullptr;
350 int screen = DefaultScreen(display);
353 if (strstr(_glXQueryExtensionsString(display, screen),
"GLX_EXT_framebuffer_sRGB") !=
nullptr) {
354 LOG_DEBUG(logger,
"GLX_EXT_framebuffer_sRGB present");
359 size_t o = attributes.size();
360 attributes.push_back(GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT);
361 attributes.push_back(GL_TRUE);
362 attributes.push_back(0);
363 attributes.push_back(0);
364 fbConfigs = _glXChooseFBConfig(display, screen, attributes.data(), &fbCount);
365 if (fbConfigs ==
nullptr || fbCount == 0) {
366 attributes.resize(o);
367 LOG_INFO(logger,
"Failed to find sRGB config.");
371 if (fbConfigs ==
nullptr || fbCount == 0) {
372 attributes.push_back(0);
373 attributes.push_back(0);
374 fbConfigs = _glXChooseFBConfig(display, screen, attributes.data(), &fbCount);
377 LOG_FATAL(logger,
"Failed to retrieve a list of framebuffer configurations.");
380 LOG_DEBUG(logger,
"Found %d matching framebuffer configs.", fbCount);
383 int best_num_samp = -1;
385 for (
int idx = 0; idx < fbCount; ++idx) {
386 XVisualInfo* vi = _glXGetVisualFromFBConfig(display, fbConfigs[idx]);
392 _glXGetFBConfigAttrib(display, fbConfigs[idx], GLX_SAMPLE_BUFFERS, &samp_buf);
393 _glXGetFBConfigAttrib(display, fbConfigs[idx], GLX_SAMPLES, &samples);
395 LOG_DEBUG(logger,
" Matching fbconfig %d, visual ID 0x%2lx: SAMPLE_BUFFERS = %d, SAMPLES = %d", idx, vi->visualid, samp_buf, samples);
397 if ((best_fbc < 0) || (samp_buf && (samples > best_num_samp) && (samples <= requestedSampleCount))) {
399 best_num_samp = samples;
405 fbConfig = fbConfigs[best_fbc];
408 LOG_DEBUG(logger,
"Requested %d samples, chose visual ID = 0x%lx", requestedSampleCount, _glXGetVisualFromFBConfig(display, fbConfig)->visualid);
413XVisualInfo* Cogs::GLContext::getVisualInfo(Display* display, GLXFBConfig fbConfig) {
414 return _glXGetVisualFromFBConfig(display, fbConfig);
Log implementation class.
@ sRGB
Value is a color and is subject to gamma correction.
constexpr Log getLogger(const char(&name)[LEN]) noexcept