VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { VkResult err; VkWin32SurfaceCreateInfoKHR sci; PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); if (!vkCreateWin32SurfaceKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); return VK_ERROR_EXTENSION_NOT_PRESENT; } memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; sci.hinstance = GetModuleHandle(NULL); sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create Vulkan surface: %s", _glfwGetVulkanResultString(err)); } return err; }
ne_status vkgfx_init_surface(void) { VkResult err = 0; VkWin32SurfaceCreateInfoKHR ci; PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = NULL; memset(&ci, 0x0, sizeof(ci)); vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(vkgfx_instance, "vkCreateWin32SurfaceKHR"); if (!vkCreateWin32SurfaceKHR) { log_entry(VK_WIN32_GFX_MODULE, LOG_CRITICAL, "Vulkan instance missing VK_KHR_win32_surface extension"); return NE_FAIL; } ci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; ci.hwnd = GetActiveWindow(); ci.hinstance = GetModuleHandle(NULL); err = vkCreateWin32SurfaceKHR(vkgfx_instance, &ci, vkgfx_allocator, &vkgfx_surface); if (err) { log_entry(VK_WIN32_GFX_MODULE, LOG_CRITICAL, "Failed to create Vulkan surface: %d", err); return NE_FAIL; } return NE_OK; }
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; }
void VulkanWindow::InitializeSurface() { #if defined ( VK_USE_PLATFORM_WIN32_KHR ) VkWin32SurfaceCreateInfoKHR win32_surface_create_info_khr {}; win32_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; win32_surface_create_info_khr.hwnd = reinterpret_cast<HWND> ( mWindowId ); win32_surface_create_info_khr.hinstance = reinterpret_cast<HINSTANCE> ( GetWindowLongPtr ( win32_surface_create_info_khr.hwnd, GWLP_HINSTANCE ) ); if ( VkResult result = vkCreateWin32SurfaceKHR ( mVulkanRenderer.GetInstance(), &win32_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) ) { std::ostringstream stream; stream << "Call to vkCreateWin32SurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } #elif defined( VK_USE_PLATFORM_XLIB_KHR ) VkXlibSurfaceCreateInfoKHR xlib_surface_create_info_khr {}; xlib_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; xlib_surface_create_info_khr.dpy = XOpenDisplay ( nullptr ); xlib_surface_create_info_khr.window = reinterpret_cast<::Window> ( mWindowId ); if ( VkResult result = vkCreateXlibSurfaceKHR ( mVulkanRenderer.GetInstance(), &xlib_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) ) { std::ostringstream stream; stream << "Call to vkCreateXlibSurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } #endif VkBool32 wsi_supported = false; vkGetPhysicalDeviceSurfaceSupportKHR ( mVulkanRenderer.GetPhysicalDevice(), mVulkanRenderer.GetQueueFamilyIndex(), mVkSurfaceKHR, &wsi_supported ); if ( !wsi_supported ) { std::ostringstream stream; stream << "WSI not supported."; throw std::runtime_error ( stream.str().c_str() ); } }
bool findSupportedQueue() { std::cout << "looking for supported queue..."; vkGetPhysicalDeviceQueueFamilyProperties( gDevices[0], &gQueueCount, nullptr ); gQueueProps.resize( gQueueCount ); vkGetPhysicalDeviceQueueFamilyProperties( gDevices[0], &gQueueCount, gQueueProps.data() ); VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; createInfo.hinstance = ghInstance; createInfo.hwnd = ghWnd; createInfo.flags = 0; gQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; gQueueInfo.pNext = nullptr; gQueueInfo.queueCount = 1; gQueueInfo.pQueuePriorities = gQueuePriorities; VkResult res = vkCreateWin32SurfaceKHR( gInstance, &createInfo, nullptr, &gSurface ); if( res != VK_SUCCESS ) { std::cout << "surface creating error " << res << std::endl; return false; } gQueueFamilyIndex = -1; for( u32 i = 0; i < gQueueCount; ++i ) { if( gQueueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT ) { VkBool32 support = false; vkGetPhysicalDeviceSurfaceSupportKHR( gDevices[0], i, gSurface, &support ); if( support == VK_TRUE ) { gQueueFamilyIndex = i; break; } } } if( gQueueFamilyIndex == -1 ) { std::cout << "supported queue not found\n" << std::endl; return false; } gQueueInfo.queueFamilyIndex = gQueueFamilyIndex; std::cout << "found\n"; return true; }
void initPlatformSpecificSurface() { VkWin32SurfaceCreateInfoKHR surfaceCreateInfo {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.pNext = nullptr; surfaceCreateInfo.flags = 0; surfaceCreateInfo.hinstance = hGlobalInstance; surfaceCreateInfo.hwnd = hWindow; VkResult result = vkCreateWin32SurfaceKHR(renderer->getVulkanInstance(), &surfaceCreateInfo, nullptr, &surface); CHECK_ERROR(result); }
void SwapChain::InitSurface(void * WindowHandle) { #if K3DPLATFORM_OS_WIN VkWin32SurfaceCreateInfoKHR SurfaceCreateInfo = {}; SurfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; SurfaceCreateInfo.hinstance = GetModuleHandle(nullptr); SurfaceCreateInfo.hwnd = (HWND)WindowHandle; K3D_VK_VERIFY(vkCreateWin32SurfaceKHR(RHIRoot::GetInstance(), &SurfaceCreateInfo, nullptr, &m_Surface)); #elif K3DPLATFORM_OS_ANDROID VkAndroidSurfaceCreateInfoKHR SurfaceCreateInfo = {}; SurfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; SurfaceCreateInfo.window = (ANativeWindow*)WindowHandle; K3D_VK_VERIFY(vkCreateAndroidSurfaceKHR(RHIRoot::GetInstance(), &SurfaceCreateInfo, nullptr, &m_Surface)); #endif }
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; }
SDL_bool WIN_Vulkan_CreateSurface(_THIS, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface) { SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr( (VkInstance)instance, "vkCreateWin32SurfaceKHR"); VkWin32SurfaceCreateInfoKHR createInfo; VkResult result; if(!_this->vulkan_config.loader_handle) { SDL_SetError("Vulkan is not loaded"); return SDL_FALSE; } if(!vkCreateWin32SurfaceKHR) { SDL_SetError(VK_KHR_WIN32_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance."); return SDL_FALSE; } createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.flags = 0; createInfo.hinstance = windowData->hinstance; createInfo.hwnd = windowData->hwnd; result = vkCreateWin32SurfaceKHR(instance, &createInfo, NULL, surface); if(result != VK_SUCCESS) { SDL_SetError("vkCreateWin32SurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result)); return SDL_FALSE; } return SDL_TRUE; }
int vlc_vk_CreateSurface(vlc_vk_t *vk) { VkInstance vkinst = vk->instance->instance; // Get current win32 HINSTANCE HINSTANCE hInst = GetModuleHandle(NULL); VkWin32SurfaceCreateInfoKHR winfo = { .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, .hinstance = hInst, .hwnd = (HWND) vk->window->handle.hwnd, }; VkResult res = vkCreateWin32SurfaceKHR(vkinst, &winfo, NULL, &vk->surface); if (res != VK_SUCCESS) { msg_Err(vk, "Failed creating Win32 surface"); return VLC_EGENERIC; } return VLC_SUCCESS; }
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_hasWin32) { VkWin32SurfaceCreateInfoKHR win32SurfaceCreateInfoKHR; memset(&win32SurfaceCreateInfoKHR, 0, sizeof(VkWin32SurfaceCreateInfoKHR)); win32SurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; win32SurfaceCreateInfoKHR.flags = 0; win32SurfaceCreateInfoKHR.hinstance = nativeDisplay; win32SurfaceCreateInfoKHR.hwnd = nativeWindow; result = vkCreateWin32SurfaceKHR(instance, &win32SurfaceCreateInfoKHR, nullptr, &surface); if (result != VK_SUCCESS) { return VK_NULL_HANDLE; } return surface; } return VK_NULL_HANDLE; }
VkSurfaceKHR NewSurface(VkInstance vkInstance, const WindowInfo* window) { VkResult error; VkSurfaceKHR surface; VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = window->exeHandle; surfaceCreateInfo.hwnd = window->windowHandle; error = vkCreateWin32SurfaceKHR(vkInstance, &surfaceCreateInfo, nullptr, &surface); Assert(error, "could not create windows surface"); //get function pointers after creating instance of vulkan GET_VULKAN_FUNCTION_POINTER_INST(vkInstance, GetPhysicalDeviceSurfaceSupportKHR); GET_VULKAN_FUNCTION_POINTER_INST(vkInstance, GetPhysicalDeviceSurfaceCapabilitiesKHR); GET_VULKAN_FUNCTION_POINTER_INST(vkInstance, GetPhysicalDeviceSurfaceFormatsKHR); GET_VULKAN_FUNCTION_POINTER_INST(vkInstance, GetPhysicalDeviceSurfacePresentModesKHR); return surface; }
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; }
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; }
_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; }
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; }
bool VulkanDevice::Init(VulkanInstance * vulkanInstance, HWND hwnd) { VkResult result; // GPU uint32_t numGPUs = 0; vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, VK_NULL_HANDLE); if (numGPUs == 0) { gLogManager->AddMessage("ERROR: No GPUs found!"); return false; } std::vector<VkPhysicalDevice> pGPUs(numGPUs); vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, pGPUs.data()); gpu = pGPUs[0]; vkGetPhysicalDeviceProperties(gpu, &gpuProperties); vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProperties); gLogManager->AddMessage("Rendering with: " + std::string(gpuProperties.deviceName)); // Queue family uint32_t numQueueFamily = 0; vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, VK_NULL_HANDLE); if (numQueueFamily == 0) { gLogManager->AddMessage("ERROR: No Queue Families were found!"); return false; } queueFamiliyProperties.resize(numQueueFamily); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, queueFamiliyProperties.data()); // Surface VkWin32SurfaceCreateInfoKHR win32SurfaceCI{}; win32SurfaceCI.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; win32SurfaceCI.hinstance = GetModuleHandle(NULL); win32SurfaceCI.hwnd = hwnd; result = vkCreateWin32SurfaceKHR(vulkanInstance->GetInstance(), &win32SurfaceCI, VK_NULL_HANDLE, &surface); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: Couldn't create Win32 Surface!"); return false; } VkBool32 * supportsPresent = new VkBool32[queueFamiliyProperties.size()]; for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++) vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent[i]); graphicsQueueFamilyIndex = UINT32_MAX; for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++) { if ((queueFamiliyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (supportsPresent[i] == VK_TRUE) { graphicsQueueFamilyIndex = i; break; } } } delete[] supportsPresent; if (graphicsQueueFamilyIndex == UINT32_MAX) { gLogManager->AddMessage("ERROR: Couldn't find a graphics queue family index!"); return false; } uint32_t numFormats; result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, VK_NULL_HANDLE); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: Couldn't get surface formats!"); return false; } VkSurfaceFormatKHR * pSurfaceFormats = new VkSurfaceFormatKHR[numFormats]; result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, pSurfaceFormats); if (numFormats == 1 && pSurfaceFormats[0].format == VK_FORMAT_UNDEFINED) format = VK_FORMAT_B8G8R8A8_UNORM; else format = pSurfaceFormats[0].format; // Device queue float pQueuePriorities[] = { 1.0f }; VkDeviceQueueCreateInfo deviceQueueCI{}; deviceQueueCI.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; deviceQueueCI.queueCount = 1; deviceQueueCI.queueFamilyIndex = graphicsQueueFamilyIndex; deviceQueueCI.pQueuePriorities = pQueuePriorities; VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.shaderClipDistance = VK_TRUE; deviceFeatures.shaderCullDistance = VK_TRUE; deviceFeatures.geometryShader = VK_TRUE; deviceFeatures.shaderTessellationAndGeometryPointSize = VK_TRUE; deviceFeatures.fillModeNonSolid = VK_TRUE; // Device VkDeviceCreateInfo deviceCI{}; deviceCI.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCI.queueCreateInfoCount = 1; deviceCI.pQueueCreateInfos = &deviceQueueCI; deviceCI.enabledExtensionCount = (uint32_t)deviceExtensions.size(); deviceCI.ppEnabledExtensionNames = deviceExtensions.data(); deviceCI.pEnabledFeatures = &deviceFeatures; result = vkCreateDevice(gpu, &deviceCI, VK_NULL_HANDLE, &device); if (result != VK_SUCCESS) { gLogManager->AddMessage("ERROR: vkCreateDevice() failed!"); return false; } vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &deviceQueue); return true; }
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 }
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; }
//============================================================================== // Vulkan初期化 //============================================================================== bool initVulkan(HINSTANCE hinst, HWND wnd) { VkResult result; //================================================== // Vulkanのインスタンス作成 //================================================== VkApplicationInfo applicationInfo = {}; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; applicationInfo.pApplicationName = APPLICATION_NAME; applicationInfo.pEngineName = APPLICATION_NAME; applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); std::vector<LPCSTR> enabledExtensionsByInstance = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pNext = nullptr; instanceCreateInfo.pApplicationInfo = &applicationInfo; if(enabledExtensionsByInstance.empty() == false) { instanceCreateInfo.enabledExtensionCount = enabledExtensionsByInstance.size(); instanceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByInstance.data(); } result = vkCreateInstance(&instanceCreateInfo, nullptr, &g_VulkanInstance); checkVulkanError(result, TEXT("Vulkanインスタンス作成失敗")); //================================================== // 物理デバイス(GPUデバイス) //================================================== // 物理デバイス数を獲得 uint32_t gpuCount = 0; vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, nullptr); assert(gpuCount > 0 && TEXT("物理デバイス数の獲得失敗")); // 物理デバイス数を列挙 std::vector<VkPhysicalDevice> physicalDevices(gpuCount); result = vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, physicalDevices.data()); checkVulkanError(result, TEXT("物理デバイスの列挙に失敗しました")); // すべてのGPU情報を格納 g_GPUs.resize(gpuCount); for(uint32_t i = 0; i < gpuCount; ++i) { g_GPUs[i].device = physicalDevices[i]; // 物理デバイスのプロパティ獲得 vkGetPhysicalDeviceProperties(g_GPUs[i].device, &g_GPUs[i].deviceProperties); // 物理デバイスのメモリプロパティ獲得 vkGetPhysicalDeviceMemoryProperties(g_GPUs[i].device, &g_GPUs[i].deviceMemoryProperties); } // ※このサンプルでは最初に列挙されたGPUデバイスを使用する g_currentGPU = g_GPUs[0]; // グラフィックス操作をサポートするキューを検索 uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, nullptr); assert(queueCount >= 1 && TEXT("物理デバイスキューの検索失敗")); std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, queueProps.data()); uint32_t graphicsQueueIndex = 0; for(graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; ++graphicsQueueIndex) { if(queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { break; } } assert(graphicsQueueIndex < queueCount && TEXT("グラフィックスをサポートするキューを見つけられませんでした")); //================================================== // Vulkanデバイス作成 //================================================== float queuePrioritie = 0.0f; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePrioritie; std::vector<LPCSTR> enabledExtensionsByDevice = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.pNext = nullptr; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; deviceCreateInfo.pEnabledFeatures = nullptr; if(enabledExtensionsByDevice.empty() == false) { deviceCreateInfo.enabledExtensionCount = enabledExtensionsByDevice.size(); deviceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByDevice.data(); } result = vkCreateDevice(g_currentGPU.device, &deviceCreateInfo, nullptr, &g_VulkanDevice); checkVulkanError(result, TEXT("Vulkanデバイス作成失敗")); // グラフィックスキュー獲得 vkGetDeviceQueue(g_VulkanDevice, graphicsQueueIndex, 0, &g_VulkanQueue); //================================================== // フェンスオブジェクト作成 //================================================== VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceCreateInfo.pNext = nullptr; fenceCreateInfo.flags = 0; result = vkCreateFence(g_VulkanDevice, &fenceCreateInfo, nullptr, &g_VulkanFence); checkVulkanError(result, TEXT("フェンスオブジェクト作成失敗")); //================================================== // 同期(セマフォ)オブジェクト作成 //================================================== VkSemaphoreCreateInfo semaphoreCreateInfo = {}; semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreCreateInfo.pNext = nullptr; semaphoreCreateInfo.flags = 0; // コマンドバッファ実行用セマフォ作成 result = vkCreateSemaphore(g_VulkanDevice, &semaphoreCreateInfo, nullptr, &g_VulkanSemahoreRenderComplete); checkVulkanError(result, TEXT("コマンドバッファ実行用セマフォ作成失敗")); //================================================== // コマンドプール作製 //================================================== VkCommandPoolCreateInfo cmdPoolInfo = {}; cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmdPoolInfo.queueFamilyIndex = 0; cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = vkCreateCommandPool(g_VulkanDevice, &cmdPoolInfo, nullptr, &g_VulkanCommandPool); checkVulkanError(result, TEXT("コマンドプール作成失敗")); //================================================== // コマンドバッファ作成 //================================================== // メモリを確保. g_commandBuffers.resize(SWAP_CHAIN_COUNT); VkCommandBufferAllocateInfo commandBufferAllocateInfo = {}; commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; commandBufferAllocateInfo.pNext = nullptr; commandBufferAllocateInfo.commandPool = g_VulkanCommandPool; commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; commandBufferAllocateInfo.commandBufferCount = SWAP_CHAIN_COUNT; result = vkAllocateCommandBuffers(g_VulkanDevice, &commandBufferAllocateInfo, g_commandBuffers.data()); checkVulkanError(result, TEXT("コマンドバッファ作成失敗")); //================================================== // OS(今回はWin32)用のサーフェスを作成する //================================================== VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = hinst; surfaceCreateInfo.hwnd = wnd; result = vkCreateWin32SurfaceKHR(g_VulkanInstance, &surfaceCreateInfo, nullptr, &g_VulkanSurface); checkVulkanError(result, TEXT("サーフェス作成失敗")); //================================================== // スワップチェーンを作成する //================================================== VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; VkColorSpaceKHR imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; uint32_t surfaceFormatCount = 0; result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, nullptr); checkVulkanError(result, TEXT("サポートしているカラーフォーマット数の獲得失敗")); std::vector<VkSurfaceFormatKHR> surfaceFormats; surfaceFormats.resize(surfaceFormatCount); result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, surfaceFormats.data()); checkVulkanError(result, TEXT("サポートしているカラーフォーマットの獲得失敗")); // 一致するカラーフォーマットを検索する bool isFind = false; for(const auto& surfaceFormat : surfaceFormats) { if(imageFormat == surfaceFormat.format && imageColorSpace == surfaceFormat.colorSpace) { isFind = true; break; } } if(isFind == false) { imageFormat = surfaceFormats[0].format; imageColorSpace = surfaceFormats[0].colorSpace; } // サーフェスの機能を獲得する VkSurfaceCapabilitiesKHR surfaceCapabilities; VkSurfaceTransformFlagBitsKHR surfaceTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( g_currentGPU.device, g_VulkanSurface, &surfaceCapabilities); checkVulkanError(result, TEXT("サーフェスの機能の獲得失敗")); if((surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0) { surfaceTransform = surfaceCapabilities.currentTransform; } // プレゼント機能を獲得する VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; uint32_t presentModeCount; result = vkGetPhysicalDeviceSurfacePresentModesKHR( g_currentGPU.device, g_VulkanSurface, &presentModeCount, nullptr); checkVulkanError(result, TEXT("プレゼント機能数の獲得失敗")); std::vector<VkPresentModeKHR> presentModes; presentModes.resize(presentModeCount); result = vkGetPhysicalDeviceSurfacePresentModesKHR( g_currentGPU.device, g_VulkanSurface, &presentModeCount, presentModes.data()); checkVulkanError(result, TEXT("プレゼント機能の獲得失敗")); for(const auto& presentModeInfo : presentModes) { if(presentModeInfo == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if(presentModeInfo == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } presentModes.clear(); uint32_t desiredSwapChainImageCount = surfaceCapabilities.minImageCount + 1; if(surfaceCapabilities.maxImageCount > 0 && desiredSwapChainImageCount > surfaceCapabilities.maxImageCount) { desiredSwapChainImageCount = surfaceCapabilities.maxImageCount; } // スワップチェーン作成 VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCreateInfo.pNext = nullptr; swapchainCreateInfo.flags = 0; swapchainCreateInfo.surface = g_VulkanSurface; swapchainCreateInfo.minImageCount = desiredSwapChainImageCount; swapchainCreateInfo.imageFormat = imageFormat; swapchainCreateInfo.imageColorSpace = imageColorSpace; swapchainCreateInfo.imageExtent = { SCREEN_WIDTH, SCREEN_HEIGHT }; swapchainCreateInfo.imageArrayLayers = 1; swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainCreateInfo.queueFamilyIndexCount = 0; swapchainCreateInfo.pQueueFamilyIndices = nullptr; swapchainCreateInfo.preTransform = surfaceTransform; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainCreateInfo.presentMode = presentMode; swapchainCreateInfo.clipped = VK_TRUE; swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; result = vkCreateSwapchainKHR(g_VulkanDevice, &swapchainCreateInfo, nullptr, &g_VulkanSwapChain); checkVulkanError(result, TEXT("サーフェス作成失敗")); //================================================== // イメージの作成 //================================================== uint32_t swapChainCount = 0; result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, nullptr); checkVulkanError(result, TEXT("スワップチェーンイメージ数の獲得失敗")); g_backBuffersTextures.resize(swapChainCount); std::vector<VkImage> images; images.resize(swapChainCount); result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, images.data()); checkVulkanError(result, TEXT("スワップチェーンイメージの獲得失敗")); for(uint32_t i = 0; i < swapChainCount; ++i) { g_backBuffersTextures[i].image = images[i]; } images.clear(); //================================================== // イメージビューの生成 //================================================== for(auto& backBuffer : g_backBuffersTextures) { VkImageViewCreateInfo imageViewCreateInfo = {}; imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.pNext = nullptr; imageViewCreateInfo.flags = 0; imageViewCreateInfo.image = backBuffer.image; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.format = imageFormat; imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; imageViewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &backBuffer.view); checkVulkanError(result, TEXT("イメージビューの作成失敗")); setImageLayout( g_VulkanDevice, g_commandBuffers[g_currentBufferIndex], backBuffer.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } //================================================== // 深度ステンシルバッファの生成 //================================================== VkFormat depthFormat = VK_FORMAT_D24_UNORM_S8_UINT; VkImageTiling imageTiling; VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(g_currentGPU.device, depthFormat, &formatProperties); if(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { imageTiling = VK_IMAGE_TILING_LINEAR; } else if(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { imageTiling = VK_IMAGE_TILING_OPTIMAL; } else { checkVulkanError(VK_RESULT_MAX_ENUM, TEXT("サポートされていないフォーマットです")); return false; } VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.pNext = nullptr; imageCreateInfo.flags = 0; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = depthFormat; imageCreateInfo.extent.width = SCREEN_WIDTH; imageCreateInfo.extent.height = SCREEN_HEIGHT; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = imageTiling; imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.queueFamilyIndexCount = 0; imageCreateInfo.pQueueFamilyIndices = nullptr; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; result = vkCreateImage(g_VulkanDevice, &imageCreateInfo, nullptr, &g_depthBufferTexture.image); checkVulkanError(result, TEXT("深度テクスチャ用イメージビュー作成失敗")); // メモリ要件を獲得 VkMemoryRequirements memoryRequirements; vkGetImageMemoryRequirements(g_VulkanDevice, g_depthBufferTexture.image, &memoryRequirements); VkFlags requirementsMask = 0; uint32_t typeBits = memoryRequirements.memoryTypeBits; uint32_t typeIndex = 0; for(const auto& memoryType : g_currentGPU.deviceMemoryProperties.memoryTypes) { if((typeBits & 0x1) == 1) { if((memoryType.propertyFlags & requirementsMask) == requirementsMask) { break; } } typeBits >>= 1; ++typeIndex; } // メモリ確保 VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.pNext = nullptr; allocInfo.allocationSize = memoryRequirements.size; allocInfo.memoryTypeIndex = typeIndex; result = vkAllocateMemory(g_VulkanDevice, &allocInfo, nullptr, &g_depthBufferTexture.memory); checkVulkanError(result, TEXT("深度テクスチャ用メモリ確保失敗")); result = vkBindImageMemory(g_VulkanDevice, g_depthBufferTexture.image, g_depthBufferTexture.memory, 0); checkVulkanError(result, TEXT("深度テクスチャメモリにバインド失敗")); VkImageViewCreateInfo imageViewCreateInfo = {}; imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.pNext = nullptr; imageViewCreateInfo.image = g_depthBufferTexture.image; imageViewCreateInfo.format = depthFormat; imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; imageViewCreateInfo.subresourceRange.baseMipLevel = 0; imageViewCreateInfo.subresourceRange.levelCount = 1; imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; imageViewCreateInfo.subresourceRange.layerCount = 1; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.flags = 0; result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &g_depthBufferTexture.view); checkVulkanError(result, TEXT("深度テクスチャイメージビュー作成失敗")); setImageLayout( g_VulkanDevice, g_commandBuffers[g_currentBufferIndex], g_depthBufferTexture.image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); //================================================== // フレームバッファの生成 //================================================== VkImageView attachments[2]; // 0=カラーバッファ、1=深度バッファ VkFramebufferCreateInfo frameBufferCreateInfo = {}; frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; frameBufferCreateInfo.pNext = nullptr; frameBufferCreateInfo.flags = 0; frameBufferCreateInfo.renderPass = VK_NULL_HANDLE; frameBufferCreateInfo.attachmentCount = 2; frameBufferCreateInfo.pAttachments = attachments; frameBufferCreateInfo.width = SCREEN_WIDTH; frameBufferCreateInfo.height = SCREEN_HEIGHT; frameBufferCreateInfo.layers = 1; g_frameBuffers.resize(SWAP_CHAIN_COUNT); for(uint32_t i = 0; i < SWAP_CHAIN_COUNT; ++i) { attachments[0] = g_backBuffersTextures[i].view; attachments[1] = g_depthBufferTexture.view; auto result = vkCreateFramebuffer(g_VulkanDevice, &frameBufferCreateInfo, nullptr, &g_frameBuffers[i]); checkVulkanError(result, TEXT("フレームバッファ作成失敗")); } return true; }
VkResult create_surface(VkInstance vk_instance, VkPhysicalDevice gpu, VkDevice* out_device, DrawCommandBuffer* out_draw_command_buffer, SwapChain* out_swap_chain) { if ((out_swap_chain == nullptr) || (out_draw_command_buffer == nullptr)) { return VK_ERROR_INITIALIZATION_FAILED; } VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = out_swap_chain->instance; surfaceCreateInfo.hwnd = out_swap_chain->window; VK_THROW(vkCreateWin32SurfaceKHR(vk_instance, &surfaceCreateInfo, NULL, &(out_swap_chain->surface))); uint32_t queue_count; vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, nullptr); assert(queue_count > 0); std::vector<VkBool32> support_presentable_swap_chain(queue_count); std::vector<VkQueueFamilyProperties> properties(queue_count); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, properties.data()); for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { vkGetPhysicalDeviceSurfaceSupportKHR(gpu, qidx, out_swap_chain->surface, &(support_presentable_swap_chain[qidx])); } uint32_t graphics_queue = UINT32_MAX; uint32_t swap_chain_queue = UINT32_MAX; for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { if (check_flag(properties[qidx].queueFlags, VK_QUEUE_GRAPHICS_BIT) && properties[qidx].queueCount > 0) { graphics_queue = qidx; if (support_presentable_swap_chain[qidx]) { swap_chain_queue = qidx; break; } } } if (swap_chain_queue == UINT32_MAX) // Can't find a graphic queue that also support swap chain. Select two different queue. { for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { if (support_presentable_swap_chain[qidx] && (properties[qidx].queueCount > 0)) { swap_chain_queue = qidx; break; } } } // Generate error if could not find both a graphics and a present queue if ((graphics_queue == UINT32_MAX) || (swap_chain_queue == UINT32_MAX)) { vkDestroySurfaceKHR(vk_instance, out_swap_chain->surface, nullptr); out_swap_chain->surface = nullptr; return VK_ERROR_INITIALIZATION_FAILED; } uint32_t format_count; VK_THROW(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, out_swap_chain->surface, &format_count, NULL)); std::vector<VkSurfaceFormatKHR> surface_formats(format_count); VK_THROW(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, out_swap_chain->surface, &format_count, surface_formats.data())); // 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 (format_count == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED) { out_swap_chain->surface_format.format = VK_FORMAT_B8G8R8A8_UNORM; out_swap_chain->surface_format.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; } else { assert(format_count > 0); out_swap_chain->surface_format = surface_formats[0]; } VK_THROW(create_device(gpu, graphics_queue, swap_chain_queue, out_device)); vkGetDeviceQueue(*out_device, graphics_queue, 0, &out_draw_command_buffer->draw_queue); vkGetDeviceQueue(*out_device, swap_chain_queue, 0, &out_swap_chain->present_queue); out_draw_command_buffer->queue_family_idx = graphics_queue; out_swap_chain->queue_family_idx = swap_chain_queue; out_swap_chain->gpu = gpu; return VK_SUCCESS; }
//[-------------------------------------------------------] //[ 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); } }
FVulkanSwapChain::FVulkanSwapChain(VkInstance Instance, FVulkanDevice& InDevice, void* WindowHandle, EPixelFormat& InOutPixelFormat, uint32 Width, uint32 Height, uint32* InOutDesiredNumBackBuffers, TArray<VkImage>& OutImages) : SwapChain(VK_NULL_HANDLE) , Device(InDevice) , Surface(VK_NULL_HANDLE) , CurrentImageIndex(-1) , SemaphoreIndex(0) { #if PLATFORM_WINDOWS VkWin32SurfaceCreateInfoKHR SurfaceCreateInfo; FMemory::Memzero(SurfaceCreateInfo); SurfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; SurfaceCreateInfo.hinstance = GetModuleHandle(nullptr); SurfaceCreateInfo.hwnd = (HWND)WindowHandle; VERIFYVULKANRESULT(vkCreateWin32SurfaceKHR(Instance, &SurfaceCreateInfo, nullptr, &Surface)); #elif PLATFORM_ANDROID VkAndroidSurfaceCreateInfoKHR SurfaceCreateInfo; FMemory::Memzero(SurfaceCreateInfo); SurfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; SurfaceCreateInfo.window = (ANativeWindow*)WindowHandle; VERIFYVULKANRESULT(vkCreateAndroidSurfaceKHR(Instance, &SurfaceCreateInfo, nullptr, &Surface)); #else static_assert(false, "Unsupported Vulkan platform!"); #endif // Find Pixel format for presentable images VkSurfaceFormatKHR CurrFormat; FMemory::Memzero(CurrFormat); { uint32 NumFormats; VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkGetPhysicalDeviceSurfaceFormatsKHR(Device.GetPhysicalHandle(), Surface, &NumFormats, nullptr)); check(NumFormats > 0); TArray<VkSurfaceFormatKHR> Formats; Formats.AddZeroed(NumFormats); VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkGetPhysicalDeviceSurfaceFormatsKHR(Device.GetPhysicalHandle(), Surface, &NumFormats, Formats.GetData())); if (Formats.Num() == 1 && Formats[0].format == VK_FORMAT_UNDEFINED && InOutPixelFormat == PF_Unknown) { InOutPixelFormat = PF_B8G8R8A8; } else if (InOutPixelFormat == PF_Unknown) { // Reverse lookup check(Formats[0].format != VK_FORMAT_UNDEFINED); for (int32 Index = 0; Index < PF_MAX; ++Index) { if (Formats[0].format == GPixelFormats[Index].PlatformFormat) { InOutPixelFormat = (EPixelFormat)Index; CurrFormat = Formats[0]; break; } } } else { VkFormat PlatformFormat = UEToVkFormat(InOutPixelFormat, false); bool bSupported = false; for (int32 Index = 0; Index < Formats.Num(); ++Index) { if (Formats[Index].format == PlatformFormat) { bSupported = true; CurrFormat = Formats[Index]; break; } } check(bSupported); } } VkFormat PlatformFormat = UEToVkFormat(InOutPixelFormat, false); //#todo-rco: Check multiple Gfx Queues? VkBool32 bSupportsPresent = VK_FALSE; VERIFYVULKANRESULT(VulkanRHI::vkGetPhysicalDeviceSurfaceSupportKHR(Device.GetPhysicalHandle(), Device.GetQueue()->GetFamilyIndex(), Surface, &bSupportsPresent)); //#todo-rco: Find separate present queue if the gfx one doesn't support presents check(bSupportsPresent); // Fetch present mode VkPresentModeKHR PresentMode = VK_PRESENT_MODE_FIFO_KHR; #if !PLATFORM_ANDROID { uint32 NumFoundPresentModes = 0; VERIFYVULKANRESULT(VulkanRHI::vkGetPhysicalDeviceSurfacePresentModesKHR(Device.GetPhysicalHandle(), Surface, &NumFoundPresentModes, nullptr)); check(NumFoundPresentModes > 0); TArray<VkPresentModeKHR> FoundPresentModes; FoundPresentModes.AddZeroed(NumFoundPresentModes); VERIFYVULKANRESULT(VulkanRHI::vkGetPhysicalDeviceSurfacePresentModesKHR(Device.GetPhysicalHandle(), Surface, &NumFoundPresentModes, FoundPresentModes.GetData())); bool bFoundDesiredMode = false; for (size_t i = 0; i < NumFoundPresentModes; i++) { if (FoundPresentModes[i] == PresentMode) { bFoundDesiredMode = true; break; } } if (!bFoundDesiredMode) { UE_LOG(LogVulkanRHI, Warning, TEXT("Couldn't find Present Mode %d!"), (int32)PresentMode); PresentMode = FoundPresentModes[0]; } } #endif // Check the surface properties and formats VkSurfaceCapabilitiesKHR SurfProperties; VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device.GetPhysicalHandle(), Surface, &SurfProperties)); VkSurfaceTransformFlagBitsKHR PreTransform; if (SurfProperties.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { PreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { PreTransform = SurfProperties.currentTransform; } // 0 means no limit, so use the requested number uint32 DesiredNumBuffers = SurfProperties.maxImageCount > 0 ? FMath::Clamp(*InOutDesiredNumBackBuffers, SurfProperties.minImageCount, SurfProperties.maxImageCount) : *InOutDesiredNumBackBuffers; VkSwapchainCreateInfoKHR SwapChainInfo; FMemory::Memzero(SwapChainInfo); SwapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; SwapChainInfo.surface = Surface; SwapChainInfo.minImageCount = DesiredNumBuffers; SwapChainInfo.imageFormat = CurrFormat.format; SwapChainInfo.imageColorSpace = CurrFormat.colorSpace; SwapChainInfo.imageExtent.width = PLATFORM_ANDROID ? Width : (SurfProperties.currentExtent.width == -1 ? Width : SurfProperties.currentExtent.width); SwapChainInfo.imageExtent.height = PLATFORM_ANDROID ? Height : (SurfProperties.currentExtent.height == -1 ? Height : SurfProperties.currentExtent.height); SwapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; SwapChainInfo.preTransform = PreTransform; SwapChainInfo.imageArrayLayers = 1; SwapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; SwapChainInfo.presentMode = PresentMode; SwapChainInfo.oldSwapchain = VK_NULL_HANDLE; SwapChainInfo.clipped = VK_TRUE; SwapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; *InOutDesiredNumBackBuffers = DesiredNumBuffers; VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkCreateSwapchainKHR(Device.GetInstanceHandle(), &SwapChainInfo, nullptr, &SwapChain)); uint32 NumSwapChainImages; VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkGetSwapchainImagesKHR(Device.GetInstanceHandle(), SwapChain, &NumSwapChainImages, nullptr)); OutImages.AddUninitialized(NumSwapChainImages); VERIFYVULKANRESULT_EXPANDED(VulkanRHI::vkGetSwapchainImagesKHR(Device.GetInstanceHandle(), SwapChain, &NumSwapChainImages, OutImages.GetData())); ImageAcquiredSemaphore.AddUninitialized(DesiredNumBuffers); for (uint32 BufferIndex = 0; BufferIndex < DesiredNumBuffers; ++BufferIndex) { ImageAcquiredSemaphore[BufferIndex] = new FVulkanSemaphore(Device); } }
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; }