Split swap chain class into header and implementation
This commit is contained in:
parent
78f9881ebf
commit
abd68cc451
5 changed files with 668 additions and 658 deletions
|
|
@ -1,5 +1,5 @@
|
|||
file(GLOB BASE_SRC "*.cpp" "*.hpp" "../external/imgui/*.cpp")
|
||||
file(GLOB BASE_HEADERS "*.hpp")
|
||||
file(GLOB BASE_SRC "*.cpp" "*.hpp" "*.h" "../external/imgui/*.cpp")
|
||||
file(GLOB BASE_HEADERS "*.hpp" "*.h")
|
||||
|
||||
set(KTX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../external/ktx)
|
||||
set(KTX_SOURCES
|
||||
|
|
|
|||
589
base/VulkanSwapChain.cpp
Normal file
589
base/VulkanSwapChain.cpp
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Class wrapping access to the swap chain
|
||||
*
|
||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
|
||||
*
|
||||
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "VulkanSwapChain.h"
|
||||
|
||||
/** @brief Creates the platform specific surface abstraction of the native platform window used for presentation */
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
void VulkanSwapChain::initSurface(void* platformHandle, void* platformWindow)
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
void VulkanSwapChain::initSurface(ANativeWindow* window)
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
void VulkanSwapChain::initSurface(wl_display *display, wl_surface *window)
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
void VulkanSwapChain::initSurface(xcb_connection_t* connection, xcb_window_t window)
|
||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
||||
void VulkanSwapChain::initSurface(void* view)
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
void VulkanSwapChain::initSurface(uint32_t width, uint32_t height)
|
||||
#endif
|
||||
{
|
||||
VkResult err = VK_SUCCESS;
|
||||
|
||||
// Create the os-specific surface
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle;
|
||||
surfaceCreateInfo.hwnd = (HWND)platformWindow;
|
||||
err = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.window = window;
|
||||
err = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
||||
VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
|
||||
surfaceCreateInfo.pNext = NULL;
|
||||
surfaceCreateInfo.flags = 0;
|
||||
surfaceCreateInfo.pView = view;
|
||||
err = vkCreateIOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||
VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
|
||||
surfaceCreateInfo.pNext = NULL;
|
||||
surfaceCreateInfo.flags = 0;
|
||||
surfaceCreateInfo.pView = view;
|
||||
err = vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, NULL, &surface);
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
createDirect2DisplaySurface(width, height);
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.display = display;
|
||||
surfaceCreateInfo.surface = window;
|
||||
err = vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.connection = connection;
|
||||
surfaceCreateInfo.window = window;
|
||||
err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#endif
|
||||
|
||||
if (err != VK_SUCCESS) {
|
||||
vks::tools::exitFatal("Could not create surface!", err);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
vks::tools::exitFatal("Could not find a graphics and/or presenting queue!", -1);
|
||||
}
|
||||
|
||||
// todo : Add support for separate graphics and presenting queue
|
||||
if (graphicsQueueNodeIndex != presentQueueNodeIndex)
|
||||
{
|
||||
vks::tools::exitFatal("Separate graphics and presenting queues are not supported yet!", -1);
|
||||
}
|
||||
|
||||
queueNodeIndex = graphicsQueueNodeIndex;
|
||||
|
||||
// Get list of supported surface formats
|
||||
uint32_t formatCount;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL));
|
||||
assert(formatCount > 0);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data()));
|
||||
|
||||
// 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
|
||||
if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
|
||||
{
|
||||
colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
colorSpace = surfaceFormats[0].colorSpace;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate over the list of available surface format and
|
||||
// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
|
||||
bool found_B8G8R8A8_UNORM = false;
|
||||
for (auto&& surfaceFormat : surfaceFormats)
|
||||
{
|
||||
if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM)
|
||||
{
|
||||
colorFormat = surfaceFormat.format;
|
||||
colorSpace = surfaceFormat.colorSpace;
|
||||
found_B8G8R8A8_UNORM = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// in case VK_FORMAT_B8G8R8A8_UNORM is not available
|
||||
// select the first available color format
|
||||
if (!found_B8G8R8A8_UNORM)
|
||||
{
|
||||
colorFormat = surfaceFormats[0].format;
|
||||
colorSpace = surfaceFormats[0].colorSpace;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set instance, physical and logical device to use for the swapchain and get all required function pointers
|
||||
*
|
||||
* @param instance Vulkan instance to use
|
||||
* @param physicalDevice Physical device used to query properties and formats relevant to the swapchain
|
||||
* @param device Logical representation of the device to create the swapchain for
|
||||
*
|
||||
*/
|
||||
void VulkanSwapChain::connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
|
||||
{
|
||||
this->instance = instance;
|
||||
this->physicalDevice = physicalDevice;
|
||||
this->device = device;
|
||||
fpGetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
|
||||
fpGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
|
||||
fpGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
|
||||
fpGetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
|
||||
|
||||
fpCreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(vkGetDeviceProcAddr(device, "vkCreateSwapchainKHR"));
|
||||
fpDestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(vkGetDeviceProcAddr(device, "vkDestroySwapchainKHR"));
|
||||
fpGetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(vkGetDeviceProcAddr(device, "vkGetSwapchainImagesKHR"));
|
||||
fpAcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(vkGetDeviceProcAddr(device, "vkAcquireNextImageKHR"));
|
||||
fpQueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(vkGetDeviceProcAddr(device, "vkQueuePresentKHR"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the swapchain and get its images with given width and height
|
||||
*
|
||||
* @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain)
|
||||
* @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain)
|
||||
* @param vsync (Optional) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode)
|
||||
*/
|
||||
void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync)
|
||||
{
|
||||
VkSwapchainKHR oldSwapchain = swapChain;
|
||||
|
||||
// Get physical device surface properties and formats
|
||||
VkSurfaceCapabilitiesKHR surfCaps;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps));
|
||||
|
||||
// Get available present modes
|
||||
uint32_t presentModeCount;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL));
|
||||
assert(presentModeCount > 0);
|
||||
|
||||
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
|
||||
|
||||
VkExtent2D swapchainExtent = {};
|
||||
// If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
|
||||
if (surfCaps.currentExtent.width == (uint32_t)-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 = surfCaps.currentExtent;
|
||||
*width = surfCaps.currentExtent.width;
|
||||
*height = surfCaps.currentExtent.height;
|
||||
}
|
||||
|
||||
|
||||
// Select a present mode for the swapchain
|
||||
|
||||
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
|
||||
// This mode waits for the vertical blank ("v-sync")
|
||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
||||
// If v-sync is not requested, try to find a mailbox mode
|
||||
// It's the lowest latency non-tearing present mode available
|
||||
if (!vsync)
|
||||
{
|
||||
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 images
|
||||
uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
|
||||
if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
|
||||
{
|
||||
desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
|
||||
}
|
||||
|
||||
// Find the transformation of the surface
|
||||
VkSurfaceTransformFlagsKHR preTransform;
|
||||
if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
|
||||
{
|
||||
// We prefer a non-rotated transform
|
||||
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
}
|
||||
else
|
||||
{
|
||||
preTransform = surfCaps.currentTransform;
|
||||
}
|
||||
|
||||
// Find a supported composite alpha format (not all devices support alpha opaque)
|
||||
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
// Simply select the first composite alpha format available
|
||||
std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
|
||||
};
|
||||
for (auto& compositeAlphaFlag : compositeAlphaFlags) {
|
||||
if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
|
||||
compositeAlpha = compositeAlphaFlag;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchainCI = {};
|
||||
swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapchainCI.pNext = NULL;
|
||||
swapchainCI.surface = surface;
|
||||
swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
|
||||
swapchainCI.imageFormat = colorFormat;
|
||||
swapchainCI.imageColorSpace = colorSpace;
|
||||
swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
|
||||
swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
|
||||
swapchainCI.imageArrayLayers = 1;
|
||||
swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchainCI.queueFamilyIndexCount = 0;
|
||||
swapchainCI.pQueueFamilyIndices = NULL;
|
||||
swapchainCI.presentMode = swapchainPresentMode;
|
||||
swapchainCI.oldSwapchain = oldSwapchain;
|
||||
// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
|
||||
swapchainCI.clipped = VK_TRUE;
|
||||
swapchainCI.compositeAlpha = compositeAlpha;
|
||||
|
||||
// Enable transfer source on swap chain images if supported
|
||||
if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
|
||||
swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
// Enable transfer destination on swap chain images if supported
|
||||
if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
|
||||
swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain));
|
||||
|
||||
// If an existing swap chain is re-created, destroy the old swap chain
|
||||
// This also cleans up all the presentable images
|
||||
if (oldSwapchain != VK_NULL_HANDLE)
|
||||
{
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
vkDestroyImageView(device, buffers[i].view, nullptr);
|
||||
}
|
||||
fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
|
||||
}
|
||||
VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL));
|
||||
|
||||
// Get the swap chain images
|
||||
images.resize(imageCount);
|
||||
VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data()));
|
||||
|
||||
// Get the swap chain buffers containing the image and imageview
|
||||
buffers.resize(imageCount);
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
VkImageViewCreateInfo colorAttachmentView = {};
|
||||
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
colorAttachmentView.pNext = NULL;
|
||||
colorAttachmentView.format = colorFormat;
|
||||
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.baseMipLevel = 0;
|
||||
colorAttachmentView.subresourceRange.levelCount = 1;
|
||||
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
|
||||
colorAttachmentView.subresourceRange.layerCount = 1;
|
||||
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorAttachmentView.flags = 0;
|
||||
|
||||
buffers[i].image = images[i];
|
||||
|
||||
colorAttachmentView.image = buffers[i].image;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the next image in the swap chain
|
||||
*
|
||||
* @param presentCompleteSemaphore (Optional) Semaphore that is signaled when the image is ready for use
|
||||
* @param imageIndex Pointer to the image index that will be increased if the next image could be acquired
|
||||
*
|
||||
* @note The function will always wait until the next image has been acquired by setting timeout to UINT64_MAX
|
||||
*
|
||||
* @return VkResult of the image acquisition
|
||||
*/
|
||||
VkResult VulkanSwapChain::acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *imageIndex)
|
||||
{
|
||||
// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
|
||||
// With that we don't have to handle VK_NOT_READY
|
||||
return fpAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, imageIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an image for presentation
|
||||
*
|
||||
* @param queue Presentation queue for presenting the image
|
||||
* @param imageIndex Index of the swapchain image to queue for presentation
|
||||
* @param waitSemaphore (Optional) Semaphore that is waited on before the image is presented (only used if != VK_NULL_HANDLE)
|
||||
*
|
||||
* @return VkResult of the queue presentation
|
||||
*/
|
||||
VkResult VulkanSwapChain::queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore)
|
||||
{
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pNext = NULL;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &swapChain;
|
||||
presentInfo.pImageIndices = &imageIndex;
|
||||
// Check if a wait semaphore has been specified to wait for before presenting the image
|
||||
if (waitSemaphore != VK_NULL_HANDLE)
|
||||
{
|
||||
presentInfo.pWaitSemaphores = &waitSemaphore;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
}
|
||||
return fpQueuePresentKHR(queue, &presentInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy and free Vulkan resources used for the swapchain
|
||||
*/
|
||||
void VulkanSwapChain::cleanup()
|
||||
{
|
||||
if (swapChain != VK_NULL_HANDLE)
|
||||
{
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
vkDestroyImageView(device, buffers[i].view, nullptr);
|
||||
}
|
||||
}
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
fpDestroySwapchainKHR(device, swapChain, nullptr);
|
||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||
}
|
||||
surface = VK_NULL_HANDLE;
|
||||
swapChain = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#if defined(_DIRECT2DISPLAY)
|
||||
/**
|
||||
* Create direct to display surface
|
||||
*/
|
||||
void VulkanSwapChain::createDirect2DisplaySurface(uint32_t width, uint32_t height)
|
||||
{
|
||||
uint32_t displayPropertyCount;
|
||||
|
||||
// Get display property
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, NULL);
|
||||
VkDisplayPropertiesKHR* pDisplayProperties = new VkDisplayPropertiesKHR[displayPropertyCount];
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, pDisplayProperties);
|
||||
|
||||
// Get plane property
|
||||
uint32_t planePropertyCount;
|
||||
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, NULL);
|
||||
VkDisplayPlanePropertiesKHR* pPlaneProperties = new VkDisplayPlanePropertiesKHR[planePropertyCount];
|
||||
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, pPlaneProperties);
|
||||
|
||||
VkDisplayKHR display = VK_NULL_HANDLE;
|
||||
VkDisplayModeKHR displayMode;
|
||||
VkDisplayModePropertiesKHR* pModeProperties;
|
||||
bool foundMode = false;
|
||||
|
||||
for(uint32_t i = 0; i < displayPropertyCount;++i)
|
||||
{
|
||||
display = pDisplayProperties[i].display;
|
||||
uint32_t modeCount;
|
||||
vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, NULL);
|
||||
pModeProperties = new VkDisplayModePropertiesKHR[modeCount];
|
||||
vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, pModeProperties);
|
||||
|
||||
for (uint32_t j = 0; j < modeCount; ++j)
|
||||
{
|
||||
const VkDisplayModePropertiesKHR* mode = &pModeProperties[j];
|
||||
|
||||
if (mode->parameters.visibleRegion.width == width && mode->parameters.visibleRegion.height == height)
|
||||
{
|
||||
displayMode = mode->displayMode;
|
||||
foundMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundMode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delete [] pModeProperties;
|
||||
}
|
||||
|
||||
if(!foundMode)
|
||||
{
|
||||
vks::tools::exitFatal("Can't find a display and a display mode!", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for a best plane we can use
|
||||
uint32_t bestPlaneIndex = UINT32_MAX;
|
||||
VkDisplayKHR* pDisplays = NULL;
|
||||
for(uint32_t i = 0; i < planePropertyCount; i++)
|
||||
{
|
||||
uint32_t planeIndex=i;
|
||||
uint32_t displayCount;
|
||||
vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, NULL);
|
||||
if (pDisplays)
|
||||
{
|
||||
delete [] pDisplays;
|
||||
}
|
||||
pDisplays = new VkDisplayKHR[displayCount];
|
||||
vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, pDisplays);
|
||||
|
||||
// Find a display that matches the current plane
|
||||
bestPlaneIndex = UINT32_MAX;
|
||||
for(uint32_t j = 0; j < displayCount; j++)
|
||||
{
|
||||
if(display == pDisplays[j])
|
||||
{
|
||||
bestPlaneIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bestPlaneIndex != UINT32_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(bestPlaneIndex == UINT32_MAX)
|
||||
{
|
||||
vks::tools::exitFatal("Can't find a plane for displaying!", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
VkDisplayPlaneCapabilitiesKHR planeCap;
|
||||
vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, bestPlaneIndex, &planeCap);
|
||||
VkDisplayPlaneAlphaFlagBitsKHR alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)0;
|
||||
|
||||
if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
|
||||
}
|
||||
|
||||
VkDisplaySurfaceCreateInfoKHR surfaceInfo{};
|
||||
surfaceInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceInfo.pNext = NULL;
|
||||
surfaceInfo.flags = 0;
|
||||
surfaceInfo.displayMode = displayMode;
|
||||
surfaceInfo.planeIndex = bestPlaneIndex;
|
||||
surfaceInfo.planeStackIndex = pPlaneProperties[bestPlaneIndex].currentStackIndex;
|
||||
surfaceInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
surfaceInfo.globalAlpha = 1.0;
|
||||
surfaceInfo.alphaMode = alphaMode;
|
||||
surfaceInfo.imageExtent.width = width;
|
||||
surfaceInfo.imageExtent.height = height;
|
||||
|
||||
VkResult result = vkCreateDisplayPlaneSurfaceKHR(instance, &surfaceInfo, NULL, &surface);
|
||||
if (result !=VK_SUCCESS) {
|
||||
vks::tools::exitFatal("Failed to create surface!", result);
|
||||
}
|
||||
|
||||
delete[] pDisplays;
|
||||
delete[] pModeProperties;
|
||||
delete[] pDisplayProperties;
|
||||
delete[] pPlaneProperties;
|
||||
}
|
||||
#endif
|
||||
76
base/VulkanSwapChain.h
Normal file
76
base/VulkanSwapChain.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Class wrapping access to the swap chain
|
||||
*
|
||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
|
||||
*
|
||||
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "VulkanTools.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "VulkanAndroid.h"
|
||||
#endif
|
||||
|
||||
typedef struct _SwapChainBuffers {
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
} SwapChainBuffer;
|
||||
|
||||
class VulkanSwapChain
|
||||
{
|
||||
private:
|
||||
VkInstance instance;
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkSurfaceKHR surface;
|
||||
// Function pointers
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR fpQueuePresentKHR;
|
||||
public:
|
||||
VkFormat colorFormat;
|
||||
VkColorSpaceKHR colorSpace;
|
||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
||||
uint32_t imageCount;
|
||||
std::vector<VkImage> images;
|
||||
std::vector<SwapChainBuffer> buffers;
|
||||
uint32_t queueNodeIndex = UINT32_MAX;
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
void initSurface(void* platformHandle, void* platformWindow);
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
void initSurface(ANativeWindow* window);
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
void initSurface(wl_display* display, wl_surface* window);
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
void initSurface(xcb_connection_t* connection, xcb_window_t window);
|
||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
||||
void initSurface(void* view);
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
void initSurface(uint32_t width, uint32_t height);
|
||||
void createDirect2DisplaySurface(uint32_t width, uint32_t height);
|
||||
#endif
|
||||
void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device);
|
||||
void create(uint32_t* width, uint32_t* height, bool vsync = false);
|
||||
VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t* imageIndex);
|
||||
VkResult queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE);
|
||||
void cleanup();
|
||||
};
|
||||
|
|
@ -1,655 +0,0 @@
|
|||
/*
|
||||
* Class wrapping access to the swap chain
|
||||
*
|
||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
|
||||
*
|
||||
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "VulkanTools.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "VulkanAndroid.h"
|
||||
#endif
|
||||
|
||||
// Macro to get a procedure address based on a vulkan instance
|
||||
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk"#entrypoint)); \
|
||||
if (fp##entrypoint == NULL) \
|
||||
{ \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Macro to get a procedure address based on a vulkan device
|
||||
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk"#entrypoint)); \
|
||||
if (fp##entrypoint == NULL) \
|
||||
{ \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
typedef struct _SwapChainBuffers {
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
} SwapChainBuffer;
|
||||
|
||||
class VulkanSwapChain
|
||||
{
|
||||
private:
|
||||
VkInstance instance;
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkSurfaceKHR surface;
|
||||
// Function pointers
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR fpQueuePresentKHR;
|
||||
public:
|
||||
VkFormat colorFormat;
|
||||
VkColorSpaceKHR colorSpace;
|
||||
/** @brief Handle to the current swap chain, required for recreation */
|
||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
||||
uint32_t imageCount;
|
||||
std::vector<VkImage> images;
|
||||
std::vector<SwapChainBuffer> buffers;
|
||||
/** @brief Queue family index of the detected graphics and presenting device queue */
|
||||
uint32_t queueNodeIndex = UINT32_MAX;
|
||||
|
||||
/** @brief Creates the platform specific surface abstraction of the native platform window used for presentation */
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
void initSurface(void* platformHandle, void* platformWindow)
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
void initSurface(ANativeWindow* window)
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
void initSurface(wl_display *display, wl_surface *window)
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
void initSurface(xcb_connection_t* connection, xcb_window_t window)
|
||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
||||
void initSurface(void* view)
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
void initSurface(uint32_t width, uint32_t height)
|
||||
#endif
|
||||
{
|
||||
VkResult err = VK_SUCCESS;
|
||||
|
||||
// Create the os-specific surface
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle;
|
||||
surfaceCreateInfo.hwnd = (HWND)platformWindow;
|
||||
err = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.window = window;
|
||||
err = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
||||
VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
|
||||
surfaceCreateInfo.pNext = NULL;
|
||||
surfaceCreateInfo.flags = 0;
|
||||
surfaceCreateInfo.pView = view;
|
||||
err = vkCreateIOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||
VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
|
||||
surfaceCreateInfo.pNext = NULL;
|
||||
surfaceCreateInfo.flags = 0;
|
||||
surfaceCreateInfo.pView = view;
|
||||
err = vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, NULL, &surface);
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
createDirect2DisplaySurface(width, height);
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.display = display;
|
||||
surfaceCreateInfo.surface = window;
|
||||
err = vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.connection = connection;
|
||||
surfaceCreateInfo.window = window;
|
||||
err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
|
||||
#endif
|
||||
|
||||
if (err != VK_SUCCESS) {
|
||||
vks::tools::exitFatal("Could not create surface!", err);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
vks::tools::exitFatal("Could not find a graphics and/or presenting queue!", -1);
|
||||
}
|
||||
|
||||
// todo : Add support for separate graphics and presenting queue
|
||||
if (graphicsQueueNodeIndex != presentQueueNodeIndex)
|
||||
{
|
||||
vks::tools::exitFatal("Separate graphics and presenting queues are not supported yet!", -1);
|
||||
}
|
||||
|
||||
queueNodeIndex = graphicsQueueNodeIndex;
|
||||
|
||||
// Get list of supported surface formats
|
||||
uint32_t formatCount;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL));
|
||||
assert(formatCount > 0);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data()));
|
||||
|
||||
// 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
|
||||
if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
|
||||
{
|
||||
colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
colorSpace = surfaceFormats[0].colorSpace;
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate over the list of available surface format and
|
||||
// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
|
||||
bool found_B8G8R8A8_UNORM = false;
|
||||
for (auto&& surfaceFormat : surfaceFormats)
|
||||
{
|
||||
if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM)
|
||||
{
|
||||
colorFormat = surfaceFormat.format;
|
||||
colorSpace = surfaceFormat.colorSpace;
|
||||
found_B8G8R8A8_UNORM = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// in case VK_FORMAT_B8G8R8A8_UNORM is not available
|
||||
// select the first available color format
|
||||
if (!found_B8G8R8A8_UNORM)
|
||||
{
|
||||
colorFormat = surfaceFormats[0].format;
|
||||
colorSpace = surfaceFormats[0].colorSpace;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set instance, physical and logical device to use for the swapchain and get all required function pointers
|
||||
*
|
||||
* @param instance Vulkan instance to use
|
||||
* @param physicalDevice Physical device used to query properties and formats relevant to the swapchain
|
||||
* @param device Logical representation of the device to create the swapchain for
|
||||
*
|
||||
*/
|
||||
void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
|
||||
{
|
||||
this->instance = instance;
|
||||
this->physicalDevice = physicalDevice;
|
||||
this->device = device;
|
||||
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
|
||||
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
|
||||
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
|
||||
GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
|
||||
GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
|
||||
GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
|
||||
GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
|
||||
GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the swapchain and get its images with given width and height
|
||||
*
|
||||
* @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain)
|
||||
* @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain)
|
||||
* @param vsync (Optional) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode)
|
||||
*/
|
||||
void create(uint32_t *width, uint32_t *height, bool vsync = false)
|
||||
{
|
||||
VkSwapchainKHR oldSwapchain = swapChain;
|
||||
|
||||
// Get physical device surface properties and formats
|
||||
VkSurfaceCapabilitiesKHR surfCaps;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps));
|
||||
|
||||
// Get available present modes
|
||||
uint32_t presentModeCount;
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL));
|
||||
assert(presentModeCount > 0);
|
||||
|
||||
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
|
||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
|
||||
|
||||
VkExtent2D swapchainExtent = {};
|
||||
// If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
|
||||
if (surfCaps.currentExtent.width == (uint32_t)-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 = surfCaps.currentExtent;
|
||||
*width = surfCaps.currentExtent.width;
|
||||
*height = surfCaps.currentExtent.height;
|
||||
}
|
||||
|
||||
|
||||
// Select a present mode for the swapchain
|
||||
|
||||
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
|
||||
// This mode waits for the vertical blank ("v-sync")
|
||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
||||
// If v-sync is not requested, try to find a mailbox mode
|
||||
// It's the lowest latency non-tearing present mode available
|
||||
if (!vsync)
|
||||
{
|
||||
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 images
|
||||
uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
|
||||
if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
|
||||
{
|
||||
desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
|
||||
}
|
||||
|
||||
// Find the transformation of the surface
|
||||
VkSurfaceTransformFlagsKHR preTransform;
|
||||
if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
|
||||
{
|
||||
// We prefer a non-rotated transform
|
||||
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
}
|
||||
else
|
||||
{
|
||||
preTransform = surfCaps.currentTransform;
|
||||
}
|
||||
|
||||
// Find a supported composite alpha format (not all devices support alpha opaque)
|
||||
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
// Simply select the first composite alpha format available
|
||||
std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
|
||||
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
|
||||
};
|
||||
for (auto& compositeAlphaFlag : compositeAlphaFlags) {
|
||||
if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
|
||||
compositeAlpha = compositeAlphaFlag;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchainCI = {};
|
||||
swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapchainCI.pNext = NULL;
|
||||
swapchainCI.surface = surface;
|
||||
swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
|
||||
swapchainCI.imageFormat = colorFormat;
|
||||
swapchainCI.imageColorSpace = colorSpace;
|
||||
swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
|
||||
swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
|
||||
swapchainCI.imageArrayLayers = 1;
|
||||
swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchainCI.queueFamilyIndexCount = 0;
|
||||
swapchainCI.pQueueFamilyIndices = NULL;
|
||||
swapchainCI.presentMode = swapchainPresentMode;
|
||||
swapchainCI.oldSwapchain = oldSwapchain;
|
||||
// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
|
||||
swapchainCI.clipped = VK_TRUE;
|
||||
swapchainCI.compositeAlpha = compositeAlpha;
|
||||
|
||||
// Enable transfer source on swap chain images if supported
|
||||
if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
|
||||
swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
// Enable transfer destination on swap chain images if supported
|
||||
if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
|
||||
swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain));
|
||||
|
||||
// If an existing swap chain is re-created, destroy the old swap chain
|
||||
// This also cleans up all the presentable images
|
||||
if (oldSwapchain != VK_NULL_HANDLE)
|
||||
{
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
vkDestroyImageView(device, buffers[i].view, nullptr);
|
||||
}
|
||||
fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
|
||||
}
|
||||
VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL));
|
||||
|
||||
// Get the swap chain images
|
||||
images.resize(imageCount);
|
||||
VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data()));
|
||||
|
||||
// Get the swap chain buffers containing the image and imageview
|
||||
buffers.resize(imageCount);
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
VkImageViewCreateInfo colorAttachmentView = {};
|
||||
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
colorAttachmentView.pNext = NULL;
|
||||
colorAttachmentView.format = colorFormat;
|
||||
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.baseMipLevel = 0;
|
||||
colorAttachmentView.subresourceRange.levelCount = 1;
|
||||
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
|
||||
colorAttachmentView.subresourceRange.layerCount = 1;
|
||||
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorAttachmentView.flags = 0;
|
||||
|
||||
buffers[i].image = images[i];
|
||||
|
||||
colorAttachmentView.image = buffers[i].image;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the next image in the swap chain
|
||||
*
|
||||
* @param presentCompleteSemaphore (Optional) Semaphore that is signaled when the image is ready for use
|
||||
* @param imageIndex Pointer to the image index that will be increased if the next image could be acquired
|
||||
*
|
||||
* @note The function will always wait until the next image has been acquired by setting timeout to UINT64_MAX
|
||||
*
|
||||
* @return VkResult of the image acquisition
|
||||
*/
|
||||
VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *imageIndex)
|
||||
{
|
||||
// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
|
||||
// With that we don't have to handle VK_NOT_READY
|
||||
return fpAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, imageIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an image for presentation
|
||||
*
|
||||
* @param queue Presentation queue for presenting the image
|
||||
* @param imageIndex Index of the swapchain image to queue for presentation
|
||||
* @param waitSemaphore (Optional) Semaphore that is waited on before the image is presented (only used if != VK_NULL_HANDLE)
|
||||
*
|
||||
* @return VkResult of the queue presentation
|
||||
*/
|
||||
VkResult queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE)
|
||||
{
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pNext = NULL;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &swapChain;
|
||||
presentInfo.pImageIndices = &imageIndex;
|
||||
// Check if a wait semaphore has been specified to wait for before presenting the image
|
||||
if (waitSemaphore != VK_NULL_HANDLE)
|
||||
{
|
||||
presentInfo.pWaitSemaphores = &waitSemaphore;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
}
|
||||
return fpQueuePresentKHR(queue, &presentInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy and free Vulkan resources used for the swapchain
|
||||
*/
|
||||
void cleanup()
|
||||
{
|
||||
if (swapChain != VK_NULL_HANDLE)
|
||||
{
|
||||
for (uint32_t i = 0; i < imageCount; i++)
|
||||
{
|
||||
vkDestroyImageView(device, buffers[i].view, nullptr);
|
||||
}
|
||||
}
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
fpDestroySwapchainKHR(device, swapChain, nullptr);
|
||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||
}
|
||||
surface = VK_NULL_HANDLE;
|
||||
swapChain = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#if defined(_DIRECT2DISPLAY)
|
||||
/**
|
||||
* Create direct to display surface
|
||||
*/
|
||||
void createDirect2DisplaySurface(uint32_t width, uint32_t height)
|
||||
{
|
||||
uint32_t displayPropertyCount;
|
||||
|
||||
// Get display property
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, NULL);
|
||||
VkDisplayPropertiesKHR* pDisplayProperties = new VkDisplayPropertiesKHR[displayPropertyCount];
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, pDisplayProperties);
|
||||
|
||||
// Get plane property
|
||||
uint32_t planePropertyCount;
|
||||
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, NULL);
|
||||
VkDisplayPlanePropertiesKHR* pPlaneProperties = new VkDisplayPlanePropertiesKHR[planePropertyCount];
|
||||
vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, pPlaneProperties);
|
||||
|
||||
VkDisplayKHR display = VK_NULL_HANDLE;
|
||||
VkDisplayModeKHR displayMode;
|
||||
VkDisplayModePropertiesKHR* pModeProperties;
|
||||
bool foundMode = false;
|
||||
|
||||
for(uint32_t i = 0; i < displayPropertyCount;++i)
|
||||
{
|
||||
display = pDisplayProperties[i].display;
|
||||
uint32_t modeCount;
|
||||
vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, NULL);
|
||||
pModeProperties = new VkDisplayModePropertiesKHR[modeCount];
|
||||
vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, pModeProperties);
|
||||
|
||||
for (uint32_t j = 0; j < modeCount; ++j)
|
||||
{
|
||||
const VkDisplayModePropertiesKHR* mode = &pModeProperties[j];
|
||||
|
||||
if (mode->parameters.visibleRegion.width == width && mode->parameters.visibleRegion.height == height)
|
||||
{
|
||||
displayMode = mode->displayMode;
|
||||
foundMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundMode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delete [] pModeProperties;
|
||||
}
|
||||
|
||||
if(!foundMode)
|
||||
{
|
||||
vks::tools::exitFatal("Can't find a display and a display mode!", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for a best plane we can use
|
||||
uint32_t bestPlaneIndex = UINT32_MAX;
|
||||
VkDisplayKHR* pDisplays = NULL;
|
||||
for(uint32_t i = 0; i < planePropertyCount; i++)
|
||||
{
|
||||
uint32_t planeIndex=i;
|
||||
uint32_t displayCount;
|
||||
vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, NULL);
|
||||
if (pDisplays)
|
||||
{
|
||||
delete [] pDisplays;
|
||||
}
|
||||
pDisplays = new VkDisplayKHR[displayCount];
|
||||
vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, pDisplays);
|
||||
|
||||
// Find a display that matches the current plane
|
||||
bestPlaneIndex = UINT32_MAX;
|
||||
for(uint32_t j = 0; j < displayCount; j++)
|
||||
{
|
||||
if(display == pDisplays[j])
|
||||
{
|
||||
bestPlaneIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bestPlaneIndex != UINT32_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(bestPlaneIndex == UINT32_MAX)
|
||||
{
|
||||
vks::tools::exitFatal("Can't find a plane for displaying!", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
VkDisplayPlaneCapabilitiesKHR planeCap;
|
||||
vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, bestPlaneIndex, &planeCap);
|
||||
VkDisplayPlaneAlphaFlagBitsKHR alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)0;
|
||||
|
||||
if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
|
||||
}
|
||||
else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR)
|
||||
{
|
||||
alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
|
||||
}
|
||||
|
||||
VkDisplaySurfaceCreateInfoKHR surfaceInfo{};
|
||||
surfaceInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceInfo.pNext = NULL;
|
||||
surfaceInfo.flags = 0;
|
||||
surfaceInfo.displayMode = displayMode;
|
||||
surfaceInfo.planeIndex = bestPlaneIndex;
|
||||
surfaceInfo.planeStackIndex = pPlaneProperties[bestPlaneIndex].currentStackIndex;
|
||||
surfaceInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
surfaceInfo.globalAlpha = 1.0;
|
||||
surfaceInfo.alphaMode = alphaMode;
|
||||
surfaceInfo.imageExtent.width = width;
|
||||
surfaceInfo.imageExtent.height = height;
|
||||
|
||||
VkResult result = vkCreateDisplayPlaneSurfaceKHR(instance, &surfaceInfo, NULL, &surface);
|
||||
if (result !=VK_SUCCESS) {
|
||||
vks::tools::exitFatal("Failed to create surface!", result);
|
||||
}
|
||||
|
||||
delete[] pDisplays;
|
||||
delete[] pModeProperties;
|
||||
delete[] pDisplayProperties;
|
||||
delete[] pPlaneProperties;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
|
@ -47,10 +47,10 @@
|
|||
#include "VulkanTools.h"
|
||||
#include "VulkanDebug.h"
|
||||
#include "VulkanUIOverlay.h"
|
||||
#include "VulkanSwapChain.h"
|
||||
|
||||
#include "VulkanInitializers.hpp"
|
||||
#include "VulkanDevice.hpp"
|
||||
#include "VulkanSwapChain.hpp"
|
||||
#include "camera.hpp"
|
||||
#include "benchmark.hpp"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue