From 74e2f47bcf698801c80cbaf474cf253a76681d8f Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 22 Feb 2016 15:13:03 -1000 Subject: [PATCH] Tons of Vulkan bug fixes --- CMakeLists.txt | 2 +- include/boo/graphicsdev/Vulkan.hpp | 10 +- lib/graphicsdev/Vulkan.cpp | 172 +++++++++++++++++++++++-- lib/x11/ApplicationXlib.hpp | 40 ++++-- lib/x11/WindowXlib.cpp | 197 +++++++++++++++-------------- 5 files changed, 306 insertions(+), 115 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eeee59a..120bf89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,7 @@ else(NOT GEKKO) if(NOT (VULKAN_LIBRARY STREQUAL VULKAN_LIBRARY-NOTFOUND)) message(STATUS "Vulkan loader found; enabling Vulkan support") list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_VULKAN=1) - list(APPEND _BOO_SYS_LIBS ${VULKAN_LIBRARY}) + list(APPEND _BOO_SYS_LIBS ${VULKAN_LIBRARY} xcb X11-xcb) list(APPEND PLAT_SRCS lib/graphicsdev/Vulkan.cpp) endif() diff --git a/include/boo/graphicsdev/Vulkan.hpp b/include/boo/graphicsdev/Vulkan.hpp index cfd7f98..9371257 100644 --- a/include/boo/graphicsdev/Vulkan.hpp +++ b/include/boo/graphicsdev/Vulkan.hpp @@ -16,10 +16,16 @@ namespace boo struct VulkanContext { - std::vector m_instanceLayerNames; + struct LayerProperties + { + VkLayerProperties properties; + std::vector extensions; + }; + + std::vector m_instanceLayerProperties; + std::vector m_layerNames; std::vector m_instanceExtensionNames; VkInstance m_instance = VK_NULL_HANDLE; - std::vector m_deviceLayerNames; std::vector m_deviceExtensionNames; std::vector m_gpus; VkPhysicalDeviceProperties m_gpuProps; diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 1bc9ea3..82d5631 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -1,7 +1,7 @@ #ifdef _WIN32 #define VK_USE_PLATFORM_WIN32_KHR #else -#define VK_USE_PLATFORM_XLIB_KHR +#define VK_USE_PLATFORM_XCB_KHR #endif #include "boo/graphicsdev/Vulkan.hpp" @@ -135,6 +135,33 @@ static inline void ThrowIfFalse(bool res) Log.report(LogVisor::FatalError, "operation failed\n", res); } +static VKAPI_ATTR VkBool32 VKAPI_CALL +dbgFunc(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, + uint64_t srcObject, size_t location, int32_t msgCode, + const char *pLayerPrefix, const char *pMsg, void *pUserData) +{ + if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + Log.report(LogVisor::FatalError, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + Log.report(LogVisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { + Log.report(LogVisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { + Log.report(LogVisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + Log.report(LogVisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } + + /* + * false indicates that layer should not bail-out of an + * API call that had validation failures. This may mean that the + * app dies inside the driver due to invalid parameter(s). + * That's what would happen without validation layers, so we'll + * keep that behavior here. + */ + return false; +} + static bool MemoryTypeFromProperties(VulkanContext* ctx, uint32_t typeBits, VkFlags requirementsMask, uint32_t *typeIndex) @@ -209,19 +236,128 @@ static void SetImageLayout(VkCommandBuffer cmd, VkImage image, 1, &imageMemoryBarrier); } +static VkResult InitGlobalExtensionProperties(VulkanContext::LayerProperties& layerProps) { + VkExtensionProperties *instance_extensions; + uint32_t instance_extension_count; + VkResult res; + char *layer_name = nullptr; + + layer_name = layerProps.properties.layerName; + + do { + res = vkEnumerateInstanceExtensionProperties( + layer_name, &instance_extension_count, nullptr); + if (res) + return res; + + if (instance_extension_count == 0) { + return VK_SUCCESS; + } + + layerProps.extensions.resize(instance_extension_count); + instance_extensions = layerProps.extensions.data(); + res = vkEnumerateInstanceExtensionProperties( + layer_name, &instance_extension_count, instance_extensions); + } while (res == VK_INCOMPLETE); + + return res; +} + +/* + * Return 1 (true) if all layer names specified in check_names + * can be found in given layer properties. + */ +static void demo_check_layers(const std::vector& layerProps, + const std::vector &layerNames) { + uint32_t check_count = layerNames.size(); + uint32_t layer_count = layerProps.size(); + for (uint32_t i = 0; i < check_count; i++) { + VkBool32 found = 0; + for (uint32_t j = 0; j < layer_count; j++) { + if (!strcmp(layerNames[i], layerProps[j].properties.layerName)) { + found = 1; + } + } + if (!found) { + Log.report(LogVisor::FatalError, "Cannot find layer: %s", layerNames[i]); + } + } +} + void VulkanContext::initVulkan(const char* appName) { + if (!glslang::InitializeProcess()) + Log.report(LogVisor::FatalError, "unable to initialize glslang"); + + uint32_t instanceLayerCount; + VkLayerProperties* vkProps = nullptr; + VkResult res; + + /* + * It's possible, though very rare, that the number of + * instance layers could change. For example, installing something + * could include new layers that the loader would pick up + * between the initial query for the count and the + * request for VkLayerProperties. The loader indicates that + * by returning a VK_INCOMPLETE status and will update the + * the count parameter. + * The count parameter will be updated with the number of + * entries loaded into the data pointer - in case the number + * of layers went down or is smaller than the size given. + */ + putenv("VK_LAYER_PATH=/usr/share/vulkan/explicit_layer.d"); + do { + ThrowIfFailed(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr)); + + if (instanceLayerCount == 0) + break; + + vkProps = (VkLayerProperties *)realloc(vkProps, instanceLayerCount * sizeof(VkLayerProperties)); + + res = vkEnumerateInstanceLayerProperties(&instanceLayerCount, vkProps); + } while (res == VK_INCOMPLETE); + + /* + * Now gather the extension list for each instance layer. + */ + for (uint32_t i=0 ; im_graphicsQueueFamilyIndex; ThrowIfFailed(vkCreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_cmdPool)); ThrowIfFailed(vkCreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_dynamicCmdPool)); diff --git a/lib/x11/ApplicationXlib.hpp b/lib/x11/ApplicationXlib.hpp index 6c5c823..825bfaa 100644 --- a/lib/x11/ApplicationXlib.hpp +++ b/lib/x11/ApplicationXlib.hpp @@ -25,12 +25,15 @@ DBusConnection* RegisterDBus(const char* appName, bool& isFirst); #include "XlibCommon.hpp" #include +#if BOO_HAS_VULKAN +#include +#endif + namespace boo { static LogVisor::LogModule Log("boo::ApplicationXlib"); XlibCursors X_CURSORS; -int XCB_GLX_EVENT_BASE = 0; int XINPUT_OPCODE = 0; static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) @@ -110,8 +113,9 @@ static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) } IWindow* _WindowXlibNew(const std::string& title, - Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, bool useVulkan); + Display* display, void* xcbConn, + int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, + GLXContext lastCtx, bool useVulkan); static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2) { @@ -169,10 +173,13 @@ class ApplicationXlib final : public IApplication XFontSet m_fontset; XIMStyle m_bestStyle = 0; int m_xDefaultScreen = 0; - int m_xcbFd, m_dbusFd, m_maxFd; + int m_x11Fd, m_dbusFd, m_maxFd; +#if BOO_HAS_VULKAN /* Vulkan enable */ bool m_useVulkan = true; + xcb_connection_t* m_xcbConn; +#endif void _deletedWindow(IWindow* window) { @@ -256,6 +263,16 @@ public: return; } +#if BOO_HAS_VULKAN + /* Cast Display to XCB connection for vulkan */ + m_xcbConn = XGetXCBConnection(m_xDisp); + if (!m_xcbConn) + { + Log.report(LogVisor::FatalError, "Can't cast Display to XCB connection for Vulkan"); + return; + } +#endif + /* Configure locale */ if (!XSupportsLocale()) { Log.report(LogVisor::FatalError, "X does not support locale %s.", @@ -316,9 +333,9 @@ public: XkbSetDetectableAutoRepeat(m_xDisp, True, nullptr); /* Get file descriptors of xcb and dbus interfaces */ - m_xcbFd = ConnectionNumber(m_xDisp); + m_x11Fd = ConnectionNumber(m_xDisp); dbus_connection_get_unix_fd(m_dbus, &m_dbusFd); - m_maxFd = MAX(m_xcbFd, m_dbusFd); + m_maxFd = MAX(m_x11Fd, m_dbusFd); XFlush(m_xDisp); } @@ -375,7 +392,7 @@ public: { fd_set fds; FD_ZERO(&fds); - FD_SET(m_xcbFd, &fds); + FD_SET(m_x11Fd, &fds); FD_SET(m_dbusFd, &fds); if (pselect(m_maxFd+1, &fds, NULL, NULL, NULL, &origmask) < 0) { @@ -384,7 +401,7 @@ public: break; } - if (FD_ISSET(m_xcbFd, &fds)) + if (FD_ISSET(m_x11Fd, &fds)) { XLockDisplay(m_xDisp); while (XPending(m_xDisp)) @@ -458,8 +475,13 @@ public: IWindow* newWindow(const std::string& title) { - IWindow* newWindow = _WindowXlibNew(title, m_xDisp, m_xDefaultScreen, m_xIM, +#if BOO_HAS_VULKAN + IWindow* newWindow = _WindowXlibNew(title, m_xDisp, m_xcbConn, m_xDefaultScreen, m_xIM, m_bestStyle, m_fontset, m_lastGlxCtx, m_useVulkan); +#else + IWindow* newWindow = _WindowXlibNew(title, m_xDisp, nullptr, m_xDefaultScreen, m_xIM, + m_bestStyle, m_fontset, m_lastGlxCtx, false); +#endif m_windows[(Window)newWindow->getPlatformHandle()] = newWindow; return newWindow; } diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index f47d627..edf4bd1 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -3,8 +3,11 @@ #include "boo/IApplication.hpp" #include "boo/graphicsdev/GL.hpp" -#define VK_USE_PLATFORM_XLIB_KHR +#if BOO_HAS_VULKAN +#define VK_USE_PLATFORM_XCB_KHR #include "boo/graphicsdev/Vulkan.hpp" +#include +#endif #include #include @@ -60,7 +63,7 @@ static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) return 0; } -static const std::vector> ContextAttribList = +static const int ContextAttribList[7][7] = { { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 5, @@ -70,10 +73,12 @@ static const std::vector> ContextAttribList = { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 4, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 }, { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 }, { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 2, @@ -445,9 +450,9 @@ public: s_glxError = false; XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - for (const std::vector& attribs : ContextAttribList) + for (int i=0 ; i::value ; ++i) { - m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, attribs.data()); + m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribList[i]); if (m_glxCtx) break; } @@ -542,9 +547,9 @@ public: { s_glxError = false; XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - for (const std::vector& attribs : ContextAttribList) + for (int i=0 ; i::value ; ++i) { - m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, attribs.data()); + m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[i]); if (m_mainCtx) break; } @@ -565,9 +570,9 @@ public: { s_glxError = false; XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - for (const std::vector& attribs : ContextAttribList) + for (int i=0 ; i::value ; ++i) { - m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, attribs.data()); + m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[i]); if (m_loadCtx) break; } @@ -589,8 +594,9 @@ public: #if BOO_HAS_VULKAN struct GraphicsContextXlibVulkan : GraphicsContextXlib { + xcb_connection_t* m_xcbConn; VulkanContext* m_ctx; - VkSurfaceKHR m_surface; + VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkFormat m_format; GLXFBConfig m_fbconfig = 0; @@ -612,84 +618,11 @@ public: IWindowCallback* m_callback; GraphicsContextXlibVulkan(IWindow* parentWindow, - Display* display, int defaultScreen, + Display* display, xcb_connection_t* xcbConn, int defaultScreen, VulkanContext* ctx, uint32_t& visualIdOut) : GraphicsContextXlib(EGraphicsAPI::Vulkan, EPixelFormat::RGBA8, parentWindow, display), - m_ctx(ctx) + m_xcbConn(xcbConn), m_ctx(ctx) { - if (ctx->m_instance == VK_NULL_HANDLE) - ctx->initVulkan(APP->getProcessName().c_str()); - - VulkanContext::Window& m_windowCtx = - *ctx->m_windows.emplace(std::make_pair(parentWindow, - std::make_unique())).first->second; - m_dataFactory = new class VulkanDataFactory(this, ctx); - - VkXlibSurfaceCreateInfoKHR surfaceInfo = {}; - surfaceInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - surfaceInfo.dpy = display; - surfaceInfo.window = parentWindow->getPlatformHandle(); - ThrowIfFailed(vkCreateXlibSurfaceKHR(ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); - - /* Iterate over each queue to learn whether it supports presenting */ - VkBool32 *supportsPresent = (VkBool32*)malloc(ctx->m_queueCount * sizeof(VkBool32)); - for (uint32_t i=0 ; im_queueCount ; ++i) - vkGetPhysicalDeviceSurfaceSupportKHR(ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); - - /* Search for a graphics queue and a present queue in the array of queue - * families, try to find one that supports both */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - { - /* First window, init device */ - for (uint32_t i=0 ; im_queueCount; ++i) - { - if ((ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) - { - if (supportsPresent[i] == VK_TRUE) - { - m_ctx->m_graphicsQueueFamilyIndex = i; - break; - } - } - } - - /* Generate error if could not find a queue that supports both a graphics - * and present */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - Log.report(LogVisor::FatalError, - "Could not find a queue that supports both graphics and present"); - - m_ctx->initDevice(); - } - else - { - /* Subsequent window, verify present */ - if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) - Log.report(LogVisor::FatalError, "subsequent surface doesn't support present"); - } - free(supportsPresent); - - - /* Get the list of VkFormats that are supported */ - uint32_t formatCount; - ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->m_gpus[0], m_surface, &formatCount, nullptr)); - VkSurfaceFormatKHR* surfFormats = (VkSurfaceFormatKHR*)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); - ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->m_gpus[0], m_surface, &formatCount, surfFormats)); - - /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, - * the surface has no preferred format. Otherwise, at least one - * supported format will be returned. */ - if (formatCount >= 1) - { - if (surfFormats[0].format == VK_FORMAT_UNDEFINED) - m_format = VK_FORMAT_B8G8R8A8_UNORM; - else - m_format = surfFormats[0].format; - } - else - Log.report(LogVisor::FatalError, "no surface formats available for Vulkan swapchain"); - - /* Query framebuffer configurations */ GLXFBConfig* fbConfigs = nullptr; int numFBConfigs = 0; @@ -746,12 +679,6 @@ public: return; } - if (!vkGetPhysicalDeviceXlibPresentationSupportKHR(ctx->m_gpus[0], ctx->m_graphicsQueueFamilyIndex, display, m_visualid)) - { - Log.report(LogVisor::FatalError, "unable to find vulkan-compatible pixel format"); - return; - } - visualIdOut = m_visualid; } @@ -805,6 +732,85 @@ public: Log.report(LogVisor::FatalError, "unable to resolve glXWaitVideoSyncSGI"); } + if (m_ctx->m_instance == VK_NULL_HANDLE) + m_ctx->initVulkan(APP->getUniqueName().c_str()); + + VulkanContext::Window& m_windowCtx = + *m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, + std::make_unique())).first->second; + + VkXcbSurfaceCreateInfoKHR surfaceInfo = {}; + surfaceInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + surfaceInfo.connection = m_xcbConn; + surfaceInfo.window = m_parentWindow->getPlatformHandle(); + ThrowIfFailed(vkCreateXcbSurfaceKHR(m_ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); + + /* Iterate over each queue to learn whether it supports presenting */ + VkBool32 *supportsPresent = (VkBool32*)malloc(m_ctx->m_queueCount * sizeof(VkBool32)); + for (uint32_t i=0 ; im_queueCount ; ++i) + vkGetPhysicalDeviceSurfaceSupportKHR(m_ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); + + /* Search for a graphics queue and a present queue in the array of queue + * families, try to find one that supports both */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) + { + /* First window, init device */ + for (uint32_t i=0 ; im_queueCount; ++i) + { + if ((m_ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) + { + if (supportsPresent[i] == VK_TRUE) + { + m_ctx->m_graphicsQueueFamilyIndex = i; + break; + } + } + } + + /* Generate error if could not find a queue that supports both a graphics + * and present */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) + Log.report(LogVisor::FatalError, + "Could not find a queue that supports both graphics and present"); + + m_ctx->initDevice(); + } + else + { + /* Subsequent window, verify present */ + if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) + Log.report(LogVisor::FatalError, "subsequent surface doesn't support present"); + } + free(supportsPresent); + + if (!vkGetPhysicalDeviceXcbPresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex, m_xcbConn, m_visualid)) + { + Log.report(LogVisor::FatalError, "XCB visual doesn't support vulkan present"); + return; + } + + /* Get the list of VkFormats that are supported */ + uint32_t formatCount; + ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, nullptr)); + VkSurfaceFormatKHR* surfFormats = (VkSurfaceFormatKHR*)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); + ThrowIfFailed(vkGetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, surfFormats)); + + + /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, + * the surface has no preferred format. Otherwise, at least one + * supported format will be returned. */ + if (formatCount >= 1) + { + if (surfFormats[0].format == VK_FORMAT_UNDEFINED) + m_format = VK_FORMAT_B8G8R8A8_UNORM; + else + m_format = surfFormats[0].format; + } + else + Log.report(LogVisor::FatalError, "no surface formats available for Vulkan swapchain"); + + m_ctx->initSwapChain(m_windowCtx, m_surface, m_format); + /* Spawn vsync thread */ m_vsyncRunning = true; std::mutex initmt; @@ -850,6 +856,7 @@ public: }); initcv.wait(outerLk); + m_dataFactory = new class VulkanDataFactory(this, m_ctx); m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); } @@ -935,7 +942,8 @@ class WindowXlib : public IWindow public: WindowXlib(const std::string& title, - Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, + Display* display, void* xcbConn, + int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, GLXContext lastCtx, bool useVulkan) : m_xDisp(display), m_callback(nullptr), m_bestStyle(bestInputStyle) @@ -945,7 +953,7 @@ public: #if BOO_HAS_VULKAN if (useVulkan) - m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, defaultScreen, + m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen, &g_VulkanContext, m_visualId)); else #endif @@ -1941,11 +1949,12 @@ public: }; IWindow* _WindowXlibNew(const std::string& title, - Display* display, int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, + Display* display, void* xcbConn, + int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, GLXContext lastCtx, bool useVulkan) { XLockDisplay(display); - IWindow* ret = new WindowXlib(title, display, defaultScreen, xIM, bestInputStyle, fontset, lastCtx, useVulkan); + IWindow* ret = new WindowXlib(title, display, xcbConn, defaultScreen, xIM, bestInputStyle, fontset, lastCtx, useVulkan); XUnlockDisplay(display); return ret; }