Cleanup & incomplete Vulkan.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m31s

This commit is contained in:
2025-01-26 22:47:41 -05:00
parent ff8fee6e90
commit 3d5fdbc9c6
5 changed files with 166 additions and 74 deletions

View File

@@ -69,8 +69,7 @@ target_include_directories(ReWindow PUBLIC ${Event_SOURCE_DIR}/include)
set_target_properties(ReWindow PROPERTIES LINKER_LANGUAGE CXX)
if(UNIX AND NOT APPLE)
find_package(Vulkan REQUIRED)
target_link_libraries(ReWindow PUBLIC X11 Event jlog Vulkan::Vulkan)
target_link_libraries(ReWindow PUBLIC X11 Event jlog)
target_link_libraries(ReWindow PUBLIC)
add_executable(ReWindowDemo main.cpp)

View File

@@ -356,7 +356,7 @@ public:
/// This function instructs the operating system to create the actual window, and give it to us to control.
/// Calling this function, therefore, creates the real 'window' object on the operating system.
virtual void Open() = 0;
[[nodiscard]] virtual bool Open() = 0;
};
// TODO in the event that we can't find OpenGL or the Open() fails, have a way to say so without throwing an exception.
@@ -367,14 +367,16 @@ public:
void SwapBuffers() override;
void SetVsyncEnabled(bool state) override;
std::string GetGraphicsDriverVendor() override;
void Open() override;
[[nodiscard]] bool Open() override;
public:
OpenGLWindow(const std::string& title, int width, int height, uint8_t gl_major, uint8_t gl_minor);
};
class ReWindow::VulkanWindow : public RWindow {
public:
void SwapBuffers() override;
void SetVsyncEnabled(bool state) override;
std::string GetGraphicsDriverVendor() override;
void Open() override;
[[nodiscard]] bool Open() override;
VulkanWindow(const std::string& title, int width, int height);
};

View File

@@ -5,6 +5,7 @@ namespace ReWindow::Logger {
using namespace Colors;
GenericLogger Info {"ReWindow", GlobalLogFile, Gray, Gray, Gray, Gray};
GenericLogger Fatal {"ReWindow::fatal", GlobalLogFile, Reds::Crimson, Gray, Gray, Reds::Crimson, White};
GenericLogger Debug {"ReWindow::debug", GlobalLogFile, Purples::Purple, Gray, Gray, Purples::Purple, White};
GenericLogger Fatal {"ReWindow::Fatal", GlobalLogFile, Reds::Crimson, Gray, Gray, Reds::Crimson, White};
GenericLogger Debug {"ReWindow::Debug", GlobalLogFile, Purples::Purple, Gray, Gray, Purples::Purple, White};
GenericLogger Error {"ReWindow::Error", GlobalLogFile, Red, Gray, Gray, Gray};
}

View File

@@ -8,48 +8,57 @@ using namespace ReWindow;
void* glx_lib = nullptr;
void* opengl_lib = nullptr;
typedef const GLubyte* (*glGetString_t)(GLenum name);
glGetString_t func_glGetString = nullptr;
namespace OpenGL {
bool constructor_success = false;
typedef Bool (*glXMakeCurrent_t)(Display *dpy, GLXDrawable drawable, GLXContext ctx);
glXMakeCurrent_t func_glXMakeCurrent = nullptr;
typedef const GLubyte *(*glGetString_t)(GLenum name);
glGetString_t glGetString = nullptr;
typedef void* (*glXGetProcAddressARB_t)(const GLubyte *procname);
glXGetProcAddressARB_t func_glXGetProcAddressARB = nullptr;
typedef Bool (*glXMakeCurrent_t)(Display *dpy, GLXDrawable drawable, GLXContext ctx);
glXMakeCurrent_t glXMakeCurrent = nullptr;
typedef void (*glXSwapBuffers_t)(Display *dpy, GLXDrawable drawable);
glXSwapBuffers_t func_glXSwapBuffers = nullptr;
typedef void *(*glXGetProcAddressARB_t)(const GLubyte *procname);
glXGetProcAddressARB_t glXGetProcAddressARB = nullptr;
typedef GLXContext (*glXCreateContext_t)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct);
glXCreateContext_t func_glXCreateContext = nullptr;
typedef void (*glXSwapBuffers_t)(Display *dpy, GLXDrawable drawable);
glXSwapBuffers_t glXSwapBuffers = nullptr;
typedef GLXFBConfig *(*glXChooseFBConfig_t)(Display *dpy, int screen, const int *attribList, int *nItems);
glXChooseFBConfig_t func_glXChooseFBConfig = nullptr;
typedef GLXContext (*glXCreateContext_t)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct);
glXCreateContext_t glXCreateContext = nullptr;
typedef XVisualInfo* (*glXGetVisualFromFBConfig_t)(Display *dpy, GLXFBConfig config);
glXGetVisualFromFBConfig_t func_glXGetVisualFromFBConfig = nullptr;
typedef GLXFBConfig *(*glXChooseFBConfig_t)(Display *dpy, int screen, const int *attribList, int *nItems);
glXChooseFBConfig_t glXChooseFBConfig = nullptr;
typedef XVisualInfo* (*glXChooseVisual_t)(Display *dpy, int screen, const int *attribList);
glXChooseVisual_t func_glXChooseVisual = nullptr;
typedef XVisualInfo *(*glXGetVisualFromFBConfig_t)(Display *dpy, GLXFBConfig config);
glXGetVisualFromFBConfig_t glXGetVisualFromFBConfig = nullptr;
typedef XVisualInfo *(*glXChooseVisual_t)(Display *dpy, int screen, const int *attribList);
glXChooseVisual_t glXChooseVisual = nullptr;
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
}
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
GLXContext gl_context;
void OpenGLWindow::SwapBuffers() {
func_glXSwapBuffers(xVars.display,xVars.window);
OpenGL::glXSwapBuffers(xVars.display,xVars.window);
}
void OpenGLWindow::SetVsyncEnabled(bool state) {
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT;
glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) func_glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalEXT");
glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) OpenGL::glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalEXT");
glXSwapIntervalEXT(xVars.display, xVars.window, state);
}
std::string OpenGLWindow::GetGraphicsDriverVendor() {
return std::string((const char*) func_glGetString(GL_VENDOR));
return std::string((const char*) OpenGL::glGetString(GL_VENDOR));
}
void OpenGLWindow::Open() {
bool OpenGLWindow::Open() {
if (!OpenGL::constructor_success)
return false;
xVars.display = XOpenDisplay(nullptr);
xVars.defaultScreen = DefaultScreen(xVars.display);
@@ -58,18 +67,22 @@ void OpenGLWindow::Open() {
xVars.xSetWindowAttributes.override_redirect = True;
xVars.xSetWindowAttributes.event_mask = ExposureMask;
auto glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)func_glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
auto glXCreateContextAttribsARB = (OpenGL::glXCreateContextAttribsARBProc) OpenGL::glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
XVisualInfo* vi = nullptr;
// Fallback to the old way if you somehow don't have this.
if (!glXCreateContextAttribsARB) {
GLint glAttributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
xVars.visual = func_glXChooseVisual(xVars.display, xVars.defaultScreen, glAttributes);
gl_context = func_glXCreateContext(xVars.display, xVars.visual, nullptr, GL_TRUE);
xVars.visual = OpenGL::glXChooseVisual(xVars.display, xVars.defaultScreen, glAttributes);
gl_context = OpenGL::glXCreateContext(xVars.display, xVars.visual, nullptr, GL_TRUE);
xVars.window = XCreateWindow(xVars.display, RootWindow(xVars.display, xVars.defaultScreen), 0, 0, width, height, 0, xVars.visual->depth,
InputOutput, xVars.visual->visual, CWBackPixel | CWColormap | CWBorderPixel | NoEventMask, &xVars.xSetWindowAttributes);
ReWindow::Logger::Debug("Created OpenGL Context with glXCreateContext.");
Logger::Debug("Created OpenGL Context with glXCreateContext.");
if (!xVars.window)
return false;
}
else {
static int visual_attributes[]
{
@@ -81,15 +94,15 @@ void OpenGLWindow::Open() {
};
int fb_count;
GLXFBConfig* fb_configurations = func_glXChooseFBConfig(xVars.display, xVars.defaultScreen, visual_attributes, &fb_count);
GLXFBConfig* fb_configurations = OpenGL::glXChooseFBConfig(xVars.display, xVars.defaultScreen, visual_attributes, &fb_count);
if (!fb_configurations || fb_count == 0)
throw std::runtime_error("Couldn't get framebuffer configuration.");
return false;
GLXFBConfig best_fbc = fb_configurations[0];
vi = func_glXGetVisualFromFBConfig(xVars.display, best_fbc);
vi = OpenGL::glXGetVisualFromFBConfig(xVars.display, best_fbc);
if (!vi)
throw std::runtime_error("Couldn't visual info from framebuffer configuration.");
return false;
xVars.xSetWindowAttributes.colormap = XCreateColormap(xVars.display, RootWindow(xVars.display, vi->screen), vi->visual, AllocNone);
xVars.window = XCreateWindow(xVars.display, RootWindow(xVars.display, vi->screen), 0, 0, width, height, 0, vi->depth, InputOutput,
@@ -99,13 +112,13 @@ void OpenGLWindow::Open() {
int context_attributes[] { GLX_CONTEXT_MAJOR_VERSION_ARB, gl_major, GLX_CONTEXT_MINOR_VERSION_ARB, gl_minor, None };
gl_context = glXCreateContextAttribsARB(xVars.display, best_fbc, nullptr, True, context_attributes);
XFree(fb_configurations);
ReWindow::Logger::Debug("Created OpenGL Context with glXCreateContextAttribsARB");
Logger::Debug("Created OpenGL Context with glXCreateContextAttribsARB");
}
if (!gl_context)
throw std::runtime_error("Couldn't create the OpenGL context.");
if (!func_glXMakeCurrent(xVars.display, xVars.window, gl_context))
throw std::runtime_error("Couldn't change OpenGL context to current.");
return false;
if (!OpenGL::glXMakeCurrent(xVars.display, xVars.window, gl_context))
return false;
if (vi)
XFree(vi);
@@ -128,12 +141,13 @@ void OpenGLWindow::Open() {
open = true;
processOnOpen();
return true;
}
OpenGLWindow::OpenGLWindow(const std::string& title, int width, int height, uint8_t gl_major, uint8_t gl_minor)
: gl_major(gl_major), gl_minor(gl_minor), RWindow(title, width, height) {
// Try this first so that in the event we have more than one window we don't double-load the library.
// Try this first.
glx_lib = dlopen("libGLX.so", RTLD_NOLOAD);
opengl_lib = dlopen("libOpenGL.so", RTLD_NOLOAD);
@@ -143,16 +157,20 @@ OpenGLWindow::OpenGLWindow(const std::string& title, int width, int height, uint
opengl_lib = dlopen("libOpenGL.so", RTLD_LAZY);
if (!opengl_lib)
throw std::runtime_error("libOpenGL.so couldn't be found in your LD_LIBRARY_PATH.");
if (!glx_lib)
throw std::runtime_error("libGLX.so couldn't be found in your LD_LIBRARY_PATH.");
Logger::Error("libOpenGL.so couldn't be found in your LD_LIBRARY_PATH."),
OpenGL::constructor_success = false;
func_glGetString = (glGetString_t) dlsym(opengl_lib, "glGetString");
func_glXMakeCurrent = (glXMakeCurrent_t) dlsym(glx_lib, "glXMakeCurrent");
func_glXGetProcAddressARB = (glXGetProcAddressARB_t) dlsym(glx_lib, "glXGetProcAddressARB");
func_glXSwapBuffers = (glXSwapBuffers_t) dlsym(glx_lib, "glXSwapBuffers");
func_glXCreateContext = (glXCreateContext_t) dlsym(glx_lib, "glXCreateContext");
func_glXChooseFBConfig = (glXChooseFBConfig_t) dlsym(glx_lib, "glXChooseFBConfig");
func_glXGetVisualFromFBConfig = (glXGetVisualFromFBConfig_t) dlsym(glx_lib, "glXGetVisualFromFBConfig");
func_glXChooseVisual = (glXChooseVisual_t) dlsym(glx_lib, "glXChooseVisual");
if (!glx_lib)
Logger::Error("libGLX.so couldn't be found in your LD_LIBRARY_PATH."),
OpenGL::constructor_success = false;
OpenGL::glGetString = (OpenGL::glGetString_t) dlsym(opengl_lib, "glGetString");
OpenGL::glXMakeCurrent = (OpenGL::glXMakeCurrent_t) dlsym(glx_lib, "glXMakeCurrent");
OpenGL::glXGetProcAddressARB = (OpenGL::glXGetProcAddressARB_t) dlsym(glx_lib, "glXGetProcAddressARB");
OpenGL::glXSwapBuffers = (OpenGL::glXSwapBuffers_t) dlsym(glx_lib, "glXSwapBuffers");
OpenGL::glXCreateContext = (OpenGL::glXCreateContext_t) dlsym(glx_lib, "glXCreateContext");
OpenGL::glXChooseFBConfig = (OpenGL::glXChooseFBConfig_t) dlsym(glx_lib, "glXChooseFBConfig");
OpenGL::glXGetVisualFromFBConfig = (OpenGL::glXGetVisualFromFBConfig_t) dlsym(glx_lib, "glXGetVisualFromFBConfig");
OpenGL::glXChooseVisual = (OpenGL::glXChooseVisual_t) dlsym(glx_lib, "glXChooseVisual");
OpenGL::constructor_success = true;
}

View File

@@ -1,11 +1,26 @@
#include <ReWindow/types/Window.h>
#include <ReWindow/Logger.h>
#include <dlfcn.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_xlib.h>
#include <set>
using namespace ReWindow;
namespace Vulkan {
bool constructor_success = false;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
PFN_vkCreateInstance vkCreateInstance = nullptr;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
PFN_vkCreateDevice vkCreateDevice = nullptr;
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
}
void* vulkan_lib = nullptr;
VkInstance vulkan_context = nullptr;
VkApplicationInfo vulkan_application_info{};
VkSurfaceKHR vulkan_surface = nullptr;
@@ -13,7 +28,21 @@ VkDevice vulkan_logical_device = nullptr;
VkQueue vulkan_graphics_queue = nullptr;
VkQueue vulkan_present_queue = nullptr;
void VulkanWindow::Open() {
// Necessary because some functions aren't available until you have a context (Vulkan is weird).
void LoadVulkanInstancedFunctions(VkInstance vulkan_ctx) {
Vulkan::vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkGetPhysicalDeviceProperties");
Vulkan::vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkEnumeratePhysicalDevices");
Vulkan::vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkGetPhysicalDeviceQueueFamilyProperties");
Vulkan::vkGetDeviceQueue = (PFN_vkGetDeviceQueue) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkGetDeviceQueue");
Vulkan::vkCreateDevice = (PFN_vkCreateDevice) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkCreateDevice");
Vulkan::vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkCreateXlibSurfaceKHR");
Vulkan::vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) Vulkan::vkGetInstanceProcAddr(vulkan_ctx, "vkGetPhysicalDeviceSurfaceSupportKHR");
}
bool VulkanWindow::Open() {
if (!Vulkan::constructor_success)
return false;
xVars.display = XOpenDisplay(nullptr);
xVars.defaultScreen = DefaultScreen(xVars.display);
@@ -37,16 +66,20 @@ void VulkanWindow::Open() {
const char* extensions[] = { "VK_KHR_surface", "VK_KHR_xlib_surface" };
create_info.enabledExtensionCount = 2;
create_info.ppEnabledExtensionNames = extensions;
if (vkCreateInstance(&create_info, nullptr, &vulkan_context) != VK_SUCCESS)
throw std::runtime_error("Couldn't create Vulkan instance.");
if (Vulkan::vkCreateInstance(&create_info, nullptr, &vulkan_context) != VK_SUCCESS) {
Logger::Error("Couldn't create Vulkan instance.");
return false;
}
LoadVulkanInstancedFunctions(vulkan_context);
XVisualInfo visual_info_t{};
visual_info_t.screen = xVars.defaultScreen;
int visual_count;
XVisualInfo* vi = XGetVisualInfo(xVars.display, VisualScreenMask, &visual_info_t, &visual_count);
if (!vi)
throw std::runtime_error("Failed to get X11 visual info.");
return false;
Colormap colormap = XCreateColormap(xVars.display, RootWindow(xVars.display, vi->screen), vi->visual, AllocNone);
xVars.xSetWindowAttributes.colormap = colormap;
@@ -55,8 +88,10 @@ void VulkanWindow::Open() {
0, 0, width, height, 0, vi->depth, InputOutput,
vi->visual, CWBackPixel | CWColormap | CWBorderPixel, &xVars.xSetWindowAttributes);
if (!xVars.window)
throw std::runtime_error("Failed to create X11 window for Vulkan.");
if (!xVars.window) {
Logger::Error("Failed to create X11 window for Vulkan.");
return false;
}
XFree(vi);
@@ -65,17 +100,21 @@ void VulkanWindow::Open() {
surface_create_info.dpy = xVars.display;
surface_create_info.window = xVars. window;
if (vkCreateXlibSurfaceKHR(vulkan_context, &surface_create_info, nullptr, &vulkan_surface) != VK_SUCCESS)
throw std::runtime_error("Failed to create Vulkan X11 surface.");
if (Vulkan::vkCreateXlibSurfaceKHR(vulkan_context, &surface_create_info, nullptr, &vulkan_surface) != VK_SUCCESS) {
Logger::Error("Failed to create Vulkan X11 surface.");
return false;
}
unsigned int device_count = 0;
vkEnumeratePhysicalDevices(vulkan_context, &device_count, nullptr);
Vulkan::vkEnumeratePhysicalDevices(vulkan_context, &device_count, nullptr);
if (device_count == 0)
throw std::runtime_error("Opening the window as Vulkan but there isn't a Vulkan compatible graphics card?");
if (device_count == 0) {
Logger::Error("Opening the window as Vulkan but there isn't a Vulkan compatible graphics card?");
return false;
}
std::vector<VkPhysicalDevice> vulkan_devices(device_count);
vkEnumeratePhysicalDevices(vulkan_context, &device_count, vulkan_devices.data());
Vulkan::vkEnumeratePhysicalDevices(vulkan_context, &device_count, vulkan_devices.data());
VkPhysicalDevice selected_device = VK_NULL_HANDLE;
@@ -83,10 +122,10 @@ void VulkanWindow::Open() {
int present_family = -1;
for (const auto& d : vulkan_devices) {
unsigned int queue_family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(d, &queue_family_count, nullptr);
Vulkan::vkGetPhysicalDeviceQueueFamilyProperties(d, &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(d, &queue_family_count, queue_families.data());
Vulkan::vkGetPhysicalDeviceQueueFamilyProperties(d, &queue_family_count, queue_families.data());
bool has_graphics = false;
bool has_present = false;
@@ -94,7 +133,8 @@ void VulkanWindow::Open() {
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { has_graphics = true; graphics_family = i; }
VkBool32 present_support = false;
vkGetPhysicalDeviceSurfaceSupportKHR(d, i, vulkan_surface, &present_support);
Vulkan::vkGetPhysicalDeviceSurfaceSupportKHR(d, i, vulkan_surface, &present_support);
if (present_support) { has_present = true; present_family = i; }
if (has_graphics && has_present) { selected_device = d; break; }
@@ -103,11 +143,13 @@ void VulkanWindow::Open() {
break;
}
if (selected_device == VK_NULL_HANDLE)
throw std::runtime_error("Opening the window using Vulkan but there isn't a Vulkan device which supports rendering & presenting?");
if (selected_device == VK_NULL_HANDLE) {
Logger::Error("There isn't a Vulkan device which supports rendering & presenting?");
return false;
}
VkPhysicalDeviceProperties device_properties;
vkGetPhysicalDeviceProperties(selected_device, &device_properties);
Vulkan::vkGetPhysicalDeviceProperties(selected_device, &device_properties);
Logger::Debug("Vulkan continuing with selected device: " + std::string(device_properties.deviceName));
float queue_prio = 1.0f;
@@ -137,11 +179,15 @@ void VulkanWindow::Open() {
device_create_info.enabledExtensionCount = device_ext.size();
device_create_info.ppEnabledExtensionNames = device_ext.data();
if (vkCreateDevice(selected_device, &device_create_info, nullptr, &vulkan_logical_device) != VK_SUCCESS)
throw std::runtime_error("Couldn't create the Vulkan logical device.");
if (Vulkan::vkCreateDevice(selected_device, &device_create_info, nullptr, &vulkan_logical_device) != VK_SUCCESS) {
Logger::Error("Couldn't create the Vulkan logical device.");
return false;
}
Vulkan::vkGetDeviceQueue(vulkan_logical_device, graphics_family, 0, &vulkan_graphics_queue);
Vulkan::vkGetDeviceQueue(vulkan_logical_device, present_family, 0, &vulkan_present_queue);
vkGetDeviceQueue(vulkan_logical_device, graphics_family, 0, &vulkan_graphics_queue);
vkGetDeviceQueue(vulkan_logical_device, present_family, 0, &vulkan_present_queue);
@@ -162,4 +208,30 @@ void VulkanWindow::Open() {
open = true;
processOnOpen();
return true;
}
void VulkanWindow::SwapBuffers() {
}
void VulkanWindow::SetVsyncEnabled(bool state) {
}
std::string VulkanWindow::GetGraphicsDriverVendor() {
}
VulkanWindow::VulkanWindow(const std::string& title, int width, int height) : RWindow(title, width, height) {
vulkan_lib = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
if (!vulkan_lib)
vulkan_lib = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
if (!vulkan_lib)
Logger::Debug("libvulkan.so couldn't be found in your LD_LIBRARY_PATH."),
Vulkan::constructor_success = false;
Vulkan::vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) dlsym(vulkan_lib,"vkGetInstanceProcAddr");
Vulkan::vkCreateInstance = (PFN_vkCreateInstance) Vulkan::vkGetInstanceProcAddr(NULL, "vkCreateInstance");
Vulkan::constructor_success = true;
}