LOGICAL swapChainPlatformConnect( struct SwapChain *swapChain, xcb_connection_t *connection, xcb_window_t *window ) #endif { VkResult result; #if defined(_WIN32) vl.surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; vl.surfaceCreateInfo.hinstance = handle; vl.surfaceCreateInfo.hwnd = window; result = vkCreateWin32SurfaceKHR( swapChain->instance, &vl.surfaceCreateInfo, NULL, &swapChain->surface ); #elif defined(__ANDROID__) vl.surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; vl.surfaceCreateInfo.window = window; result = vkCreateAndroidSurfaceKHR( swapChain->instance, &surfaceCreateInfo, NULL, &swapChain->surface ); #else vl.surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; vl.surfaceCreateInfo.connection = connection; vl.surfaceCreateInfo.window = window; result = vkCreateXcbSurfaceKHR( swapChain->instance, &surfaceCreateInfo, NULL, &swapChain->surface ); #endif return result == VK_SUCCESS; }
bool create_surface(core::c_window *window) { const core::s_window_info *window_sys_info = window->get_window_info(); #ifdef PLATFORM_WINDOWS VkWin32SurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkWin32SurfaceCreateFlagsKHR flags window_sys_info->instance, // HINSTANCE hinstance window_sys_info->handle // HWND hwnd }; VK_VERIFY (vkCreateWin32SurfaceKHR(vk_globals::instance, &surface_create_info, nullptr, &(vk_globals::surface))); #elif PLATFORM_LINUX VkXcbSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkXcbSurfaceCreateFlagsKHR flags window_sys_info->connection, // xcb_connection_t* connection window_sys_info->handle // xcb_window_t window }; VK_VERIFY (vkCreateXcbSurfaceKHR(vk_globals::instance, &surface_create_info, nullptr, &(vk_globals::surface))); #endif return true; }
VkSurfaceKHR VKTS_APIENTRY _wsiSurfaceCreate(const VkInstance instance, VKTS_NATIVE_DISPLAY nativeDisplay, VKTS_NATIVE_WINDOW nativeWindow) { if (!instance) { return VK_NULL_HANDLE; } // VkResult result; VkSurfaceKHR surface; if (g_hasXcb) { VkXcbSurfaceCreateInfoKHR xcbSurfaceCreateInfoKHR; memset(&xcbSurfaceCreateInfoKHR, 0, sizeof(VkXcbSurfaceCreateInfoKHR)); xcbSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; xcbSurfaceCreateInfoKHR.flags = 0; xcbSurfaceCreateInfoKHR.connection = XGetXCBConnection(nativeDisplay); xcbSurfaceCreateInfoKHR.window = (xcb_window_t)nativeWindow; result = vkCreateXcbSurfaceKHR(instance, &xcbSurfaceCreateInfoKHR, nullptr, &surface); if (result != VK_SUCCESS) { return VK_NULL_HANDLE; } return surface; } if (g_hasXlib) { VkXlibSurfaceCreateInfoKHR xlibSurfaceCreateInfoKHR; memset(&xlibSurfaceCreateInfoKHR, 0, sizeof(VkXlibSurfaceCreateInfoKHR)); xlibSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; xlibSurfaceCreateInfoKHR.flags = 0; xlibSurfaceCreateInfoKHR.dpy = nativeDisplay; xlibSurfaceCreateInfoKHR.window = nativeWindow; result = vkCreateXlibSurfaceKHR(instance, &xlibSurfaceCreateInfoKHR, nullptr, &surface); if (result != VK_SUCCESS) { return VK_NULL_HANDLE; } return surface; } return VK_NULL_HANDLE; }
void Window::_InitOSSurface() { VkXcbSurfaceCreateInfoKHR create_info {}; create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; create_info.connection = _xcb_connection; create_info.window = _xcb_window; ErrorCheck( vkCreateXcbSurfaceKHR( _renderer->GetVulkanInstance(), &create_info, nullptr, &_surface ) ); }
void v_window::_initOSSurface() { VkXcbSurfaceCreateInfoKHR createInfo = {}; { createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; createInfo.connection = _xcb_connection; createInfo.window = _xcb_window; } vkCreateXcbSurfaceKHR(_renderer->getInstance(),&createInfo, nullptr,&_surface); assert(_surface && "create surface faild"); }
angle::Result WindowSurfaceVkXcb::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) { VkXcbSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; createInfo.flags = 0; createInfo.connection = mXcbConnection; createInfo.window = mNativeWindowType; ANGLE_VK_TRY(context, vkCreateXcbSurfaceKHR(context->getRenderer()->getInstance(), &createInfo, nullptr, &mSurface)); xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType); xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr); ASSERT(reply); *extentsOut = gl::Extents(reply->width, reply->height, 0); free(reply); return angle::Result::Continue; }
vk::ErrorOrResult<gl::Extents> WindowSurfaceVkXcb::createSurfaceVk(RendererVk *renderer) { VkXcbSurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; createInfo.flags = 0; createInfo.connection = mXcbConnection; createInfo.window = mNativeWindowType; ANGLE_VK_TRY(vkCreateXcbSurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface)); xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType); xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr); ASSERT(reply); gl::Extents result(reply->width, reply->height, 0); free(reply); return result; }
bool VulkanCommon::CreatePresentationSurface() { #if defined(VK_USE_PLATFORM_WIN32_KHR) VkWin32SurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkWin32SurfaceCreateFlagsKHR flags Window.Instance, // HINSTANCE hinstance Window.Handle // HWND hwnd }; if( vkCreateWin32SurfaceKHR( Vulkan.Instance, &surface_create_info, nullptr, &Vulkan.PresentationSurface ) == VK_SUCCESS ) { return true; } #elif defined(VK_USE_PLATFORM_XCB_KHR) VkXcbSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkXcbSurfaceCreateFlagsKHR flags Window.Connection, // xcb_connection_t* connection Window.Handle // xcb_window_t window }; if( vkCreateXcbSurfaceKHR( Vulkan.Instance, &surface_create_info, nullptr, &Vulkan.PresentationSurface ) == VK_SUCCESS ) { return true; } #elif defined(VK_USE_PLATFORM_XLIB_KHR) VkXlibSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkXlibSurfaceCreateFlagsKHR flags Window.DisplayPtr, // Display *dpy Window.Handle // Window window }; if( vkCreateXlibSurfaceKHR( Vulkan.Instance, &surface_create_info, nullptr, &Vulkan.PresentationSurface ) == VK_SUCCESS ) { return true; } #endif std::cout << "Could not create presentation surface!" << std::endl; return false; }
//============================================================================== Error GrManagerImpl::initSurface(const GrManagerInitInfo& init) { SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); if(!SDL_GetWindowWMInfo(init.m_window->getNative().m_window, &wminfo)) { ANKI_LOGE("SDL_GetWindowWMInfo() failed"); return ErrorCode::NONE; } #if ANKI_OS == ANKI_OS_LINUX VkXcbSurfaceCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; ci.connection = XGetXCBConnection(wminfo.info.x11.display); ci.window = wminfo.info.x11.window; ANKI_VK_CHECK(vkCreateXcbSurfaceKHR(m_instance, &ci, nullptr, &m_surface)); #else #error TODO #endif return ErrorCode::NONE; }
Error GrManagerImpl::initSurface(const GrManagerInitInfo& init) { SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); if(!SDL_GetWindowWMInfo(init.m_window->getNative().m_window, &wminfo)) { ANKI_LOGE("SDL_GetWindowWMInfo() failed"); return ErrorCode::NONE; } #if ANKI_OS == ANKI_OS_LINUX VkXcbSurfaceCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; ci.connection = XGetXCBConnection(wminfo.info.x11.display); ci.window = wminfo.info.x11.window; ANKI_VK_CHECK(vkCreateXcbSurfaceKHR(m_instance, &ci, nullptr, &m_surface)); #elif ANKI_OS == ANKI_OS_WINDOWS Array<TCHAR, 512> className; GetClassName(wminfo.info.win.window, &className[0], className.getSize()); WNDCLASS wce = {}; GetClassInfo(GetModuleHandle(NULL), &className[0], &wce); VkWin32SurfaceCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; ci.hinstance = wce.hInstance; ci.hwnd = wminfo.info.win.window; ANKI_VK_CHECK(vkCreateWin32SurfaceKHR(m_instance, &ci, nullptr, &m_surface)); #else #error TODO #endif return ErrorCode::NONE; }
void VulkanContext::ReinitSurface(int width, int height) { if (surface_ != VK_NULL_HANDLE) { ILOG("Destroying Vulkan surface (%d, %d)", width_, height_); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } ILOG("Creating Vulkan surface (%d, %d)", width, height); switch (winsys_) { #ifdef _WIN32 case WINDOWSYSTEM_WIN32: { HINSTANCE connection = (HINSTANCE)winsysData1_; HWND window = (HWND)winsysData2_; RECT rc; GetClientRect(window, &rc); width = rc.right - rc.left; height = rc.bottom - rc.top; VkWin32SurfaceCreateInfoKHR win32{ VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; win32.flags = 0; win32.hwnd = window; win32.hinstance = connection; VkResult res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(__ANDROID__) case WINDOWSYSTEM_ANDROID: { ANativeWindow *wnd = (ANativeWindow *)winsysData1_; VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = wnd; VkResult res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) case WINDOWSYSTEM_XLIB: { VkXlibSurfaceCreateInfoKHR xlib = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; VkResult res = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) case WINDOWSYSTEM_XCB: { VkXCBSurfaceCreateInfoKHR xcb = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR }; xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; VkResult res = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) case WINDOWSYSTEM_WAYLAND: { VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR }; wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; VkResult res = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif default: _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); break; } width_ = width; height_ = height; }
int XdevLSwapChainVulkan::createSurface(IPXdevLWindow window) { Display* display = static_cast<Display*>(window->getInternal(XdevLInternalName("X11_DISPLAY"))); if(nullptr == display) { XDEVL_MODULEX_ERROR(XdevLSwapChainVulkan, "Could not get native X11 display information.\n"); return RET_FAILED; } Window x11window = (Window)(window->getInternal(XdevLInternalName("X11_WINDOW"))); if(None == x11window) { XDEVL_MODULEX_ERROR(XdevLSwapChainVulkan, "Could not get native X11 window information.\n"); return RET_FAILED; } // // Get the Surface extensions. // VkResult result; #if defined(_WIN32) VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle; // provided by the platform code surfaceCreateInfo.hwnd = (HWND)platformWindow; // provided by the platform code result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &m_surface); #elif defined(__ANDROID__) VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.window = window; // provided by the platform code result = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &m_surface); #else VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, nullptr, 0, XGetXCBConnection(display), (xcb_window_t)x11window }; result = vkCreateXcbSurfaceKHR(m_instance, &surfaceCreateInfo, nullptr, &m_surface); #endif if(result != VK_SUCCESS) { std::cerr << "Failed to create Vulkan surface: " << vkVkResultToString(result) << std::endl; return 1; } uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueCount, nullptr); std::vector<VkQueueFamilyProperties> queueProps(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueCount, queueProps.data()); // Will be used to present the swap chain images to the windowing system std::vector<VkBool32> supportsPresent(queueCount); for(uint32_t i = 0; i < queueCount; i++) { fpGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both uint32_t graphicsQueueNodeIndex = UINT32_MAX; uint32_t presentQueueNodeIndex = UINT32_MAX; for(uint32_t i = 0; i < queueCount; i++) { if((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if(graphicsQueueNodeIndex == UINT32_MAX) { graphicsQueueNodeIndex = i; } if(supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } } if(presentQueueNodeIndex == UINT32_MAX) { // If there's no queue that supports both present and graphics // try to find a separate present queue for(uint32_t i = 0; i < queueCount; ++i) { if(supportsPresent[i] == VK_TRUE) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if(graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { return 1; } // todo : Add support for separate graphics and presenting queue if(graphicsQueueNodeIndex != presentQueueNodeIndex) { return 1; } m_queueNodeIndex = graphicsQueueNodeIndex; // Get list of supported surface formats uint32_t formatCount; result = vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr); if(VK_SUCCESS != result) { std::cerr << "vkGetPhysicalDeviceSurfaceFormatsKHR failed: " << vkVkResultToString(result) << std::endl; return 1; } assert(formatCount > 0); std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); result = vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, surfaceFormats.data()); assert(!result); // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM if((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { // Always select the first available color format // If you need a specific format (e.g. SRGB) you'd need to // iterate over the list of available surface format and // check for it's presence m_colorFormat = surfaceFormats[0].format; } m_colorSpace = surfaceFormats[0].colorSpace; return 0; }
void createSurface( #if defined(_WIN32) HINSTANCE windowInstance, HWND window #elif defined(__linux__) xcb_connection_t *connection, xcb_window_t window #endif ) { #if defined(_WIN32) VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.pNext = NULL; surfaceCreateInfo.flags = 0; surfaceCreateInfo.hinstance = windowInstance; surfaceCreateInfo.hwnd = window; VkResult result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface); #elif defined(__linux__) VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.pNext = NULL; surfaceCreateInfo.flags = 0; surfaceCreateInfo.connection = connection; surfaceCreateInfo.window = window; VkResult result = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface); #endif assert(result == VK_SUCCESS); uint32_t queueCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); std::vector<VkQueueFamilyProperties> queueProperties(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProperties.data()); queueIndex = UINT32_MAX; std::vector<VkBool32> supportsPresenting(queueCount); for (uint32_t i = 0; i < queueCount; i++) { fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &supportsPresenting[i]); if ((queueProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (supportsPresenting[i] == VK_TRUE) { queueIndex = i; break; } } } assert(queueIndex != UINT32_MAX); uint32_t formatCount = 0; result = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL); assert(result == VK_SUCCESS && formatCount >= 1); std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); result = fpGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &formatCount, surfaceFormats.data()); assert(result == VK_SUCCESS); if (formatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) colorFormat = VK_FORMAT_B8G8R8A8_UNORM; else colorFormat = surfaceFormats[0].format; colorSpace = surfaceFormats[0].colorSpace; }
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd) { #if defined(VK_USE_PLATFORM_WIN32_KHR) VkWin32SurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkWin32SurfaceCreateFlagsKHR flags nullptr, // HINSTANCE hinstance reinterpret_cast<HWND>(hwnd) // HWND hwnd }; VkSurfaceKHR surface; VkResult res = vkCreateWin32SurfaceKHR(instance, &surface_create_info, nullptr, &surface); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateWin32SurfaceKHR failed: "); return VK_NULL_HANDLE; } return surface; #elif defined(VK_USE_PLATFORM_XLIB_KHR) // Assuming the display handles are compatible, or shared. This matches what we do in the // GL backend, but it's not ideal. Display* display = XOpenDisplay(nullptr); VkXlibSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkXlibSurfaceCreateFlagsKHR flags display, // Display* dpy reinterpret_cast<Window>(hwnd) // Window window }; VkSurfaceKHR surface; VkResult res = vkCreateXlibSurfaceKHR(instance, &surface_create_info, nullptr, &surface); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateXlibSurfaceKHR failed: "); return VK_NULL_HANDLE; } return surface; #elif defined(VK_USE_PLATFORM_XCB_KHR) // If we ever switch to using xcb, we should pass the display handle as well. Display* display = XOpenDisplay(nullptr); xcb_connection_t* connection = XGetXCBConnection(display); VkXcbSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkXcbSurfaceCreateFlagsKHR flags connection, // xcb_connection_t* connection static_cast<xcb_window_t>(reinterpret_cast<uintptr_t>(hwnd)) // xcb_window_t window }; VkSurfaceKHR surface; VkResult res = vkCreateXcbSurfaceKHR(instance, &surface_create_info, nullptr, &surface); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateXcbSurfaceKHR failed: "); return VK_NULL_HANDLE; } return surface; #elif defined(VK_USE_PLATFORM_ANDROID_KHR) VkAndroidSurfaceCreateInfoKHR surface_create_info = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void* pNext 0, // VkAndroidSurfaceCreateFlagsKHR flags reinterpret_cast<ANativeWindow*>(hwnd) // ANativeWindow* window }; VkSurfaceKHR surface; VkResult res = vkCreateAndroidSurfaceKHR(instance, &surface_create_info, nullptr, &surface); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateAndroidSurfaceKHR failed: "); return VK_NULL_HANDLE; } return surface; #else return VK_NULL_HANDLE; #endif }
//[-------------------------------------------------------] //[ Public methods ] //[-------------------------------------------------------] SwapChain::SwapChain(VulkanRenderer &vulkanRenderer, handle nativeWindowHandle) : ISwapChain(vulkanRenderer), mNativeWindowHandle(nativeWindowHandle), mVkSurfaceKHR(VK_NULL_HANDLE), mVkSwapchainKHR(VK_NULL_HANDLE), mSwapchainImageCount(0) { // Get the Vulkan instance and the Vulkan physical device const VkInstance vkInstance = vulkanRenderer.getVulkanRuntimeLinking().getVkInstance(); const IContext& context = vulkanRenderer.getContext(); const VkPhysicalDevice vkPhysicalDevice = context.getVkPhysicalDevice(); const VkDevice vkDevice = context.getVkDevice(); // Create Vulkan surface instance depending on OS #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR vkWin32SurfaceCreateInfoKHR = {}; vkWin32SurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; vkWin32SurfaceCreateInfoKHR.hinstance = reinterpret_cast<HINSTANCE>(::GetWindowLong(reinterpret_cast<HWND>(nativeWindowHandle), GWL_HINSTANCE)); vkWin32SurfaceCreateInfoKHR.hwnd = reinterpret_cast<HWND>(nativeWindowHandle); VkResult vkResult = vkCreateWin32SurfaceKHR(vkInstance, &vkWin32SurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #else #ifdef __ANDROID__ // TODO(co) Not tested - see https://github.com/SaschaWillems/Vulkan VkAndroidSurfaceCreateInfoKHR vkAndroidSurfaceCreateInfoKHR = {}; vkAndroidSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; vkAndroidSurfaceCreateInfoKHR.window = window; VkResult vkResult = vkCreateAndroidSurfaceKHR(vkInstance, &vkAndroidSurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #else // TODO(co) Not tested - see https://github.com/SaschaWillems/Vulkan VkXcbSurfaceCreateInfoKHR vkXcbSurfaceCreateInfoKHR = {}; vkXcbSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; vkXcbSurfaceCreateInfoKHR.connection = connection; vkXcbSurfaceCreateInfoKHR.window = window; VkResult vkResult = vkCreateXcbSurfaceKHR(vkInstance, &vkXcbSurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #endif #endif // Get list of supported surface formats uint32_t surfaceFormatCount = 0; vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, mVkSurfaceKHR, &surfaceFormatCount, nullptr); // assert(!vkResult); // assert(surfaceFormatCount > 0); std::vector<VkSurfaceFormatKHR> vkSurfaceFormatKHRs(surfaceFormatCount); vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, mVkSurfaceKHR, &surfaceFormatCount, vkSurfaceFormatKHRs.data()); // assert(!vkResult); // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferred format, so we assume VK_FORMAT_B8G8R8A8_UNORM VkFormat colorVkFormat; if ((surfaceFormatCount == 1) && (vkSurfaceFormatKHRs[0].format == VK_FORMAT_UNDEFINED)) { colorVkFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { // Always select the first available color format // If you need a specific format (e.g. SRGB) you'd need to // iterate over the list of available surface format and // check for it's presence colorVkFormat = vkSurfaceFormatKHRs[0].format; } VkColorSpaceKHR vkColorSpaceKHR = vkSurfaceFormatKHRs[0].colorSpace; // Get the width and height of the given native window and ensure they are never ever zero // -> See "getSafeWidthAndHeight()"-method comments for details uint32_t width = 1; uint32_t height = 1; #ifdef _WIN32 { // Get the client rectangle of the given native window RECT rect; ::GetClientRect(reinterpret_cast<HWND>(nativeWindowHandle), &rect); // Get the width and height... width = static_cast<uint32_t>(rect.right - rect.left); height = static_cast<uint32_t>(rect.bottom - rect.top); // ... and ensure that none of them is ever zero if (width < 1) { width = 1; } if (height < 1) { height = 1; } } #endif // TODO(co) Move the rest into a method VkSwapchainKHR oldVkSwapchainKHR = mVkSwapchainKHR; // Get physical device surface properties and formats VkSurfaceCapabilitiesKHR vkSurfaceCapabilitiesKHR; vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, mVkSurfaceKHR, &vkSurfaceCapabilitiesKHR); // assert(!vkResult); // Get available present modes uint32_t presentModeCount = 0; vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, mVkSurfaceKHR, &presentModeCount, nullptr); // assert(!vkResult); // assert(presentModeCount > 0); std::vector<VkPresentModeKHR> vkPresentModeKHRs(presentModeCount); vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, mVkSurfaceKHR, &presentModeCount, vkPresentModeKHRs.data()); // assert(!vkResult); // Width and height are either both -1, or both not -1. VkExtent2D swapchainExtent = {}; if (vkSurfaceCapabilitiesKHR.currentExtent.width == -1) { // If the surface size is undefined, the size is set to // the size of the images requested. swapchainExtent.width = width; swapchainExtent.height = height; } else { // If the surface size is defined, the swap chain size must match swapchainExtent = vkSurfaceCapabilitiesKHR.currentExtent; width = vkSurfaceCapabilitiesKHR.currentExtent.width; height = vkSurfaceCapabilitiesKHR.currentExtent.height; } // Prefer mailbox mode if present, it's the lowest latency non-tearing present mode VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (size_t i = 0; i < presentModeCount; ++i) { if (vkPresentModeKHRs[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (vkPresentModeKHRs[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } // Determine the number of images uint32_t desiredNumberOfSwapchainImages = vkSurfaceCapabilitiesKHR.minImageCount + 1; if ((vkSurfaceCapabilitiesKHR.maxImageCount > 0) && (desiredNumberOfSwapchainImages > vkSurfaceCapabilitiesKHR.maxImageCount)) { desiredNumberOfSwapchainImages = vkSurfaceCapabilitiesKHR.maxImageCount; } VkSurfaceTransformFlagsKHR vkSurfaceTransformFlagsKHR; if (vkSurfaceCapabilitiesKHR.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { vkSurfaceTransformFlagsKHR = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { vkSurfaceTransformFlagsKHR = vkSurfaceCapabilitiesKHR.currentTransform; } VkSwapchainCreateInfoKHR vkSwapchainCreateInfoKHR = {}; vkSwapchainCreateInfoKHR.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; vkSwapchainCreateInfoKHR.surface = mVkSurfaceKHR; vkSwapchainCreateInfoKHR.minImageCount = desiredNumberOfSwapchainImages; vkSwapchainCreateInfoKHR.imageFormat = colorVkFormat; vkSwapchainCreateInfoKHR.imageColorSpace = vkColorSpaceKHR; vkSwapchainCreateInfoKHR.imageExtent = { swapchainExtent.width, swapchainExtent.height }; vkSwapchainCreateInfoKHR.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; vkSwapchainCreateInfoKHR.preTransform = static_cast<VkSurfaceTransformFlagBitsKHR>(vkSurfaceTransformFlagsKHR); vkSwapchainCreateInfoKHR.imageArrayLayers = 1; vkSwapchainCreateInfoKHR.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; vkSwapchainCreateInfoKHR.presentMode = swapchainPresentMode; vkSwapchainCreateInfoKHR.oldSwapchain = oldVkSwapchainKHR; vkSwapchainCreateInfoKHR.clipped = true; vkSwapchainCreateInfoKHR.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; vkResult = vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfoKHR, nullptr, &mVkSwapchainKHR); // assert(!vkResult); // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable images if (VK_NULL_HANDLE != oldVkSwapchainKHR) { for (uint32_t i = 0; i < mSwapchainImageCount; ++i) { vkDestroyImageView(vkDevice, mSwapChainBuffer[i].view, nullptr); } vkDestroySwapchainKHR(vkDevice, oldVkSwapchainKHR, nullptr); } vkResult = vkGetSwapchainImagesKHR(vkDevice, mVkSwapchainKHR, &mSwapchainImageCount, nullptr); // assert(!vkResult); // Get the swap chain images mVkImages.resize(mSwapchainImageCount); vkResult = vkGetSwapchainImagesKHR(vkDevice, mVkSwapchainKHR, &mSwapchainImageCount, mVkImages.data()); // assert(!vkResult); // Get the swap chain buffers containing the image and image view mSwapChainBuffer.resize(mSwapchainImageCount); for (uint32_t i = 0; i < mSwapchainImageCount; ++i) { VkImageViewCreateInfo colorAttachmentView = {}; colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; colorAttachmentView.format = colorVkFormat; colorAttachmentView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorAttachmentView.subresourceRange.levelCount = 1; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; mSwapChainBuffer[i].image = mVkImages[i]; // Transform images from initial (undefined) to present layout Helper::setImageLayout(context.getSetupVkCommandBuffer(), mSwapChainBuffer[i].image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_ASPECT_COLOR_BIT); colorAttachmentView.image = mSwapChainBuffer[i].image; vkResult = vkCreateImageView(vkDevice, &colorAttachmentView, nullptr, &mSwapChainBuffer[i].view); // assert(!vkResult); } }
int main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Swapchain Initialization Sample"; /* * Set up swapchain: * - Get supported uses for all queues * - Try to find a queue that supports both graphics and present * - If no queue supports both, find a present queue and make sure we have a * graphics queue * - Get a list of supported formats and use the first one * - Get surface properties and present modes and use them to create a swap * chain * - Create swap chain buffers * - For each buffer, create a color attachment view and set its layout to * color attachment */ init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_connection(info); init_window_size(info, 50, 50); init_window(info); /* VULKAN_KEY_START */ // Construct the surface description: #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.hinstance = info.connection; createInfo.hwnd = info.window; res = vkCreateWin32SurfaceKHR(info.inst, &createInfo, NULL, &info.surface); #else // _WIN32 VkXcbSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.connection = info.connection; createInfo.window = info.window; res = vkCreateXcbSurfaceKHR(info.inst, &createInfo, NULL, &info.surface); #endif // _WIN32 assert(res == VK_SUCCESS); // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = (VkBool32 *)malloc(info.queue_count * sizeof(VkBool32)); for (uint32_t i = 0; i < info.queue_count; i++) { vkGetPhysicalDeviceSurfaceSupportKHR(info.gpus[0], i, info.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 uint32_t graphicsQueueNodeIndex = UINT32_MAX; for (uint32_t i = 0; i < info.queue_count; i++) { if ((info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; break; } } } free(supportsPresent); // Generate error if could not find a queue that supports both a graphics // and present if (graphicsQueueNodeIndex == UINT32_MAX) { std::cout << "Could not find a queue that supports both graphics and " "present\n"; exit(-1); } info.graphics_queue_family_index = graphicsQueueNodeIndex; init_device(info); // Get the list of VkFormats that are supported: uint32_t formatCount; res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.surface, &formatCount, NULL); assert(res == VK_SUCCESS); VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.surface, &formatCount, surfFormats); assert(res == VK_SUCCESS); // 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 && surfFormats[0].format == VK_FORMAT_UNDEFINED) { info.format = VK_FORMAT_B8G8R8A8_UNORM; } else { assert(formatCount >= 1); info.format = surfFormats[0].format; } VkSurfaceCapabilitiesKHR surfCapabilities; res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(info.gpus[0], info.surface, &surfCapabilities); assert(res == VK_SUCCESS); uint32_t presentModeCount; res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.gpus[0], info.surface, &presentModeCount, NULL); assert(res == VK_SUCCESS); VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); res = vkGetPhysicalDeviceSurfacePresentModesKHR( info.gpus[0], info.surface, &presentModeCount, presentModes); assert(res == VK_SUCCESS); VkExtent2D swapChainExtent; // width and height are either both -1, or both not -1. if (surfCapabilities.currentExtent.width == (uint32_t)-1) { // If the surface size is undefined, the size is set to // the size of the images requested. swapChainExtent.width = info.width; swapChainExtent.height = info.height; } else { // If the surface size is defined, the swap chain size must match swapChainExtent = surfCapabilities.currentExtent; } // If mailbox mode is available, use it, as is the lowest-latency non- // tearing mode. If not, try IMMEDIATE which will usually be available, // and is fastest (though it tears). If not, fall back to FIFO which is // always available. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (size_t i = 0; i < presentModeCount; i++) { if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and // queued for display): uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1; if ((surfCapabilities.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) { // Application must settle for fewer images than desired: desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; } VkSurfaceTransformFlagBitsKHR preTransform; if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { preTransform = surfCapabilities.currentTransform; } VkSwapchainCreateInfoKHR swap_chain = {}; swap_chain.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swap_chain.pNext = NULL; swap_chain.surface = info.surface; swap_chain.minImageCount = desiredNumberOfSwapChainImages; swap_chain.imageFormat = info.format; swap_chain.imageExtent.width = swapChainExtent.width; swap_chain.imageExtent.height = swapChainExtent.height; swap_chain.preTransform = preTransform; swap_chain.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swap_chain.imageArrayLayers = 1; swap_chain.presentMode = swapchainPresentMode; swap_chain.oldSwapchain = NULL; swap_chain.clipped = true; swap_chain.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swap_chain.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swap_chain.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swap_chain.queueFamilyIndexCount = 0; swap_chain.pQueueFamilyIndices = NULL; res = vkCreateSwapchainKHR(info.device, &swap_chain, NULL, &info.swap_chain); assert(res == VK_SUCCESS); res = vkGetSwapchainImagesKHR(info.device, info.swap_chain, &info.swapchainImageCount, NULL); assert(res == VK_SUCCESS); VkImage *swapchainImages = (VkImage *)malloc(info.swapchainImageCount * sizeof(VkImage)); assert(swapchainImages); res = vkGetSwapchainImagesKHR(info.device, info.swap_chain, &info.swapchainImageCount, swapchainImages); assert(res == VK_SUCCESS); info.buffers.resize(info.swapchainImageCount); // Going to need a command buffer to send the memory barriers in // set_image_layout but we couldn't have created one before we knew // what our graphics_queue_family_index is, but now that we have it, // create the command buffer init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); vkGetDeviceQueue(info.device, info.graphics_queue_family_index, 0, &info.queue); for (uint32_t i = 0; i < info.swapchainImageCount; i++) { VkImageViewCreateInfo color_image_view = {}; color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; color_image_view.pNext = NULL; color_image_view.format = info.format; color_image_view.components.r = VK_COMPONENT_SWIZZLE_R; color_image_view.components.g = VK_COMPONENT_SWIZZLE_G; color_image_view.components.b = VK_COMPONENT_SWIZZLE_B; color_image_view.components.a = VK_COMPONENT_SWIZZLE_A; color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; color_image_view.subresourceRange.baseMipLevel = 0; color_image_view.subresourceRange.levelCount = 1; color_image_view.subresourceRange.baseArrayLayer = 0; color_image_view.subresourceRange.layerCount = 1; color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; color_image_view.flags = 0; info.buffers[i].image = swapchainImages[i]; set_image_layout(info, info.buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); color_image_view.image = info.buffers[i].image; res = vkCreateImageView(info.device, &color_image_view, NULL, &info.buffers[i].view); assert(res == VK_SUCCESS); } free(swapchainImages); execute_end_command_buffer(info); execute_queue_command_buffer(info); /* VULKAN_KEY_END */ /* Clean Up */ VkCommandBuffer cmd_bufs[1] = {info.cmd}; vkFreeCommandBuffers(info.device, info.cmd_pool, 1, cmd_bufs); vkDestroyCommandPool(info.device, info.cmd_pool, NULL); for (uint32_t i = 0; i < info.swapchainImageCount; i++) { vkDestroyImageView(info.device, info.buffers[i].view, NULL); } vkDestroySwapchainKHR(info.device, info.swap_chain, NULL); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
// Creates an os specific surface // Tries to find a graphics and a present queue void initSurface( xcb_connection_t* connection, xcb_window_t window ) { VkResult err; // Create surface depending on OS VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.connection = connection; surfaceCreateInfo.window = window; err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface); // Get available queue family properties uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); std::vector<VkQueueFamilyProperties> queueProps(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data()); // Iterate over each queue to learn whether it supports presenting: // Find a queue with present support // Will be used to present the swap chain images to the windowing system std::vector<VkBool32> supportsPresent(queueCount); for (uint32_t i = 0; i < queueCount; i++) { fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both uint32_t graphicsQueueNodeIndex = UINT32_MAX; uint32_t presentQueueNodeIndex = UINT32_MAX; for (uint32_t i = 0; i < queueCount; i++) { if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (graphicsQueueNodeIndex == UINT32_MAX) { graphicsQueueNodeIndex = i; } if (supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; presentQueueNodeIndex = i; break; } } } if (presentQueueNodeIndex == UINT32_MAX) { // If there's no queue that supports both present and graphics // try to find a separate present queue for (uint32_t i = 0; i < queueCount; ++i) { if (supportsPresent[i] == VK_TRUE) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { feather::vulkan::tools::exitFatal("Could not find a graphics and/or presenting queue!", "Fatal error"); } // todo : Add support for separate graphics and presenting queue if (graphicsQueueNodeIndex != presentQueueNodeIndex) { feather::vulkan::tools::exitFatal("Separate graphics and presenting queues are not supported yet!", "Fatal error"); } queueNodeIndex = graphicsQueueNodeIndex; // Get list of supported surface formats uint32_t formatCount; err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL); assert(!err); assert(formatCount > 0); std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data()); assert(!err); // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { colorFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { // Always select the first available color format // If you need a specific format (e.g. SRGB) you'd need to // iterate over the list of available surface format and // check for it's presence colorFormat = surfaceFormats[0].format; } colorSpace = surfaceFormats[0].colorSpace; }
_agpu_swap_chain *_agpu_swap_chain::create(agpu_device *device, agpu_command_queue* graphicsCommandQueue, agpu_swap_chain_create_info *createInfo) { VkSurfaceKHR surface = VK_NULL_HANDLE; if (!graphicsCommandQueue || !createInfo) return nullptr; #if defined(_WIN32) if (!createInfo->window) return nullptr; VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(surfaceCreateInfo)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = GetModuleHandle(nullptr); surfaceCreateInfo.hwnd = (HWND)createInfo->window; auto error = vkCreateWin32SurfaceKHR(device->vulkanInstance, &surfaceCreateInfo, nullptr, &surface); #elif defined(__unix__) if(!device->displayHandle) device->displayHandle = XOpenDisplay(nullptr); if (!createInfo->window) return nullptr; VkXcbSurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(surfaceCreateInfo)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.connection = XGetXCBConnection((Display*)device->displayHandle); surfaceCreateInfo.window = (xcb_window_t)(uintptr_t)createInfo->window; auto error = vkCreateXcbSurfaceKHR(device->vulkanInstance, &surfaceCreateInfo, nullptr, &surface); #else #error unsupported platform #endif if (error) { printError("Failed to create the swap chain surface\n"); return nullptr; } agpu_command_queue *presentationQueue = graphicsCommandQueue; if (!graphicsCommandQueue->supportsPresentingSurface(surface)) { // TODO: Find a presentation queue. vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); printError("Surface presentation in different queue is not yet supported.\n"); return nullptr; } uint32_t formatCount = 0; error = device->fpGetPhysicalDeviceSurfaceFormatsKHR(device->physicalDevice, surface, &formatCount, nullptr); if (error) { vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); return nullptr; } std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount); error = device->fpGetPhysicalDeviceSurfaceFormatsKHR(device->physicalDevice, surface, &formatCount, &surfaceFormats[0]); if (error) { vkDestroySurfaceKHR(device->vulkanInstance, surface, nullptr); return nullptr; } // Create the swap chain object. auto swapChain = new agpu_swap_chain(device); swapChain->surface = surface; swapChain->graphicsQueue = graphicsCommandQueue; swapChain->presentationQueue = presentationQueue; graphicsCommandQueue->retain(); presentationQueue->retain(); // Set the format. agpu_texture_format actualFormat = createInfo->colorbuffer_format; if (formatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) { swapChain->format = mapTextureFormat(createInfo->colorbuffer_format); if (swapChain->format == VK_FORMAT_UNDEFINED) { swapChain->format = VK_FORMAT_B8G8R8A8_UNORM; actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM; } swapChain->colorSpace = surfaceFormats[0].colorSpace; } else { assert(formatCount >= 1); // Start selecting the first format. swapChain->format = surfaceFormats[0].format; swapChain->colorSpace = surfaceFormats[0].colorSpace; actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM; if(swapChain->format == VK_FORMAT_B8G8R8A8_SRGB) actualFormat = AGPU_TEXTURE_FORMAT_B8G8R8A8_UNORM_SRGB; // Try to select the expected format. auto wantedFormat = mapTextureFormat(createInfo->colorbuffer_format); for(size_t i = 0; i < formatCount; ++i) { auto &format = surfaceFormats[i]; if(format.format == wantedFormat) { swapChain->format = format.format; swapChain->colorSpace = format.colorSpace; actualFormat = createInfo->colorbuffer_format; break; } } } swapChain->agpuFormat = actualFormat; // Initialize the rest of the swap chain. if (!swapChain->initialize(createInfo)) { swapChain->release(); return nullptr; } return swapChain; }