void GetSurfaceColorSpaceAndFormat(VkPhysicalDevice physicalDevice, SurfaceInfo* surfaceInfo) { uint32_t surfaceFormatCount; VkResult error; error = GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surfaceInfo->surface, &surfaceFormatCount, nullptr); Assert(error, "could not get surface format counts, GetphysicalDeviceSurfaceFormatsKHR is probably null"); Assert(surfaceFormatCount > 0, "surfaceformatcount is less than 1"); std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount); error = GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surfaceInfo->surface, &surfaceFormatCount, surfaceFormats.data()); Assert(error, "could not get surface format counts, GetphysicalDeviceSurfaceFormatsKHR is probably null"); if (surfaceFormatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) { surfaceInfo->colorFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { surfaceInfo->colorFormat = surfaceFormats[0].format; } surfaceInfo->colorSpace = surfaceFormats[0].colorSpace; }
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; }
// 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; }
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; }
_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; }