From 7dedabba572614ffdd31a8d68c513d5f1e82e7cf Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Tue, 24 Dec 2019 21:32:38 +0100 Subject: [PATCH] source/Platform/Unix/GLXContext: Initial implementation --- source/Platform/Unix/GLXContext.cpp | 178 ++++++++++++++++++++++++++-- source/Platform/Unix/GLXContext.h | 12 ++ 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/source/Platform/Unix/GLXContext.cpp b/source/Platform/Unix/GLXContext.cpp index a488bdd..b00db35 100644 --- a/source/Platform/Unix/GLXContext.cpp +++ b/source/Platform/Unix/GLXContext.cpp @@ -1,51 +1,211 @@ +#include +#include +#include + +#include "glad_glx.h" +#include "X11SharedDisplay.h" #include "GLXContext.h" namespace sp { -GLXContext::GLXContext() -{ +static bool loadGL() { + static bool init = false; + if (!init) { + int ver; + init = true; + + ver = gladLoaderLoadGL(); + if (!ver) { + return false; + } + + Log::info("GLX: Opengl Version %d.%d loaded.", + GLAD_VERSION_MAJOR(ver), GLAD_VERSION_MINOR(ver)); + } + + return true; +} + +// Ensure that OpenGL extensions are loaded. +static bool ensureExtensionsLoaded(::Display* disp, int screen) +{ + char msg[1024]; + static bool init = false; + + if (!init) { + int ver; + init = true; + + ver = gladLoaderLoadGLX(disp, screen); + if (!ver) { + Log::warn("GLX: Could not load GLX extensions"); + return false; + } + + snprintf(msg, 1024, "GLX: GLX Version %d.%d loaded", + GLAD_VERSION_MAJOR(ver), GLAD_VERSION_MINOR(ver)); + + // Check for atleast version 1.4 + if (ver < 10004) { + Log::error("%s but atleast version 1.4 is needed.", msg); + return false; + } + + Log::info("%s.", msg); + } + + return true; +} + +GLXContext::GLXContext() : +m_disp (NULL), +m_win (0), +m_ctx (NULL) +{ } GLXContext::~GLXContext() { - + destroy(); } bool GLXContext::create(const PlatformDisplay* display) { + // Destroy any previous context first. + destroy(); + + m_disp = XGetDisplay(); + if (m_disp == NULL) { + destroy(); + Log::warn("X11: Could not open display"); + return false; + } + + m_win = (::Window) display->getHandle(); + + if (!createGLContext()) { + destroy(); + return false; + } + + return true; +} + +bool GLXContext::createGLContext() +{ + ::GLXFBConfig *fbc; + ::XVisualInfo *info; + int fbcount; + + GLint vi_attr[] = { + GLX_RGBA, + GLX_DEPTH_SIZE, 24, + GLX_DOUBLEBUFFER, 1, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None + }; + + GLint ctx_attr[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }; + + // Ensure glx extensions are loaded. + if (!ensureExtensionsLoaded(m_disp, DefaultScreen(m_disp))) { + return false; + } + + info = ::glXChooseVisual(m_disp, DefaultScreen(m_disp), vi_attr); + if (info == NULL) { + Log::warn("GLX: Could not find a valid VisualInfo."); + return false; + } + + // Setup GL settings. + fbc = glXChooseFBConfig(m_disp, DefaultScreen(m_disp), (const int*) info->visual, &fbcount); + if (fbc == NULL) { + Log::warn("GLX: Could not find FB Config."); + return false; + } + + // Create context. + m_ctx = glXCreateContextAttribsARB(m_disp, fbc[0], NULL, GL_TRUE, ctx_attr); + if (m_ctx == NULL) { + Log::warn("GLX: Failed to create context."); + return false; + } + + glXMakeCurrent(m_disp, m_win, m_ctx); + + // Load OpenGL + if (!loadGL()) { + Log::warn("GLX: Could not load OpenGL"); + return false; + } + return true; } void GLXContext::destroy() { + if (m_ctx) { + ::glXDestroyContext(m_disp, m_ctx); + m_ctx = NULL; + } + if (m_disp) { + XReleaseDisplay(); + m_disp = NULL; + } + + m_win = None; } bool GLXContext::activate() { - return true; + if (m_win && m_ctx) { + return ::glXMakeCurrent(m_disp, m_win, m_ctx); + } + return false; } bool GLXContext::deactivate() { - return true; + return ::glXMakeCurrent(m_disp, None, NULL); } bool GLXContext::isActive() const { - return true; + return ::glXGetCurrentContext() == m_ctx; } bool GLXContext::setSwapInterval(int interval) { - return true; + ensureExtensionsLoaded(m_disp, DefaultScreen(m_disp)); + + if (GLAD_GLX_MESA_swap_control) { + return glXSwapIntervalMESA(interval); + } + + if (GLAD_GLX_SGI_swap_control) { + return glXSwapIntervalSGI(interval); + } + + return false; } void GLXContext::setSize(unsigned int width, unsigned int height) { - + // TODO: Not GLX specific! move to generic GLContext class. + if (activate()) { + glViewport(0, 0, width, height); + } } void GLXContext::setSize(const Vector2u size) @@ -55,7 +215,7 @@ void GLXContext::setSize(const Vector2u size) void GLXContext::swapBuffers() { - + glXSwapBuffers(m_disp, m_win); } } // namespace sp diff --git a/source/Platform/Unix/GLXContext.h b/source/Platform/Unix/GLXContext.h index 3a5dcbe..305d789 100644 --- a/source/Platform/Unix/GLXContext.h +++ b/source/Platform/Unix/GLXContext.h @@ -4,6 +4,7 @@ // X11 OpenGL Context (glx) +#include "glad_glx.h" #include namespace sp { @@ -32,6 +33,17 @@ public : void setSize(const Vector2u size); void swapBuffers(); + +private : + bool createGLContext(); + +private : + + ::Display* m_disp; + + ::Window m_win; + + ::GLXContext m_ctx; }; } // namespace sp