Vulkan swapchain
- Filter devices with swapchain present support - Configure swapchain and images
This commit is contained in:
parent
7e59a9d2d7
commit
1aae507c11
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
#include <Boost/lockfree/spsc_queue.hpp>
|
#include <Boost/lockfree/spsc_queue.hpp>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
@ -17,6 +18,7 @@
|
|||||||
// GPU properties priority for selection
|
// GPU properties priority for selection
|
||||||
#define GPU_DISCRETE_PRIORITY 1000
|
#define GPU_DISCRETE_PRIORITY 1000
|
||||||
#define GPU_GRAPHICS_WITH_PRESENT_PRIORITY 500
|
#define GPU_GRAPHICS_WITH_PRESENT_PRIORITY 500
|
||||||
|
#define GPU_B8G8R8_SRGB_PRIORITY 10
|
||||||
|
|
||||||
#define QUEUE_FAMILY_NO_VALUE UINT32_MAX
|
#define QUEUE_FAMILY_NO_VALUE UINT32_MAX
|
||||||
|
|
||||||
@ -44,6 +46,17 @@ struct QueuesBundle
|
|||||||
VkQueue present;
|
VkQueue present;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SurfaceInfo
|
||||||
|
{
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
std::vector<VkSurfaceFormatKHR> availableFormats;
|
||||||
|
std::vector<VkPresentModeKHR> availablePresentModes;
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR format;
|
||||||
|
VkPresentModeKHR presentMode;
|
||||||
|
VkExtent2D extent;
|
||||||
|
};
|
||||||
|
|
||||||
class Renderer
|
class Renderer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -56,6 +69,10 @@ private:
|
|||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkPhysicalDevice gpu;
|
VkPhysicalDevice gpu;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
|
VkSwapchainKHR swapchain;
|
||||||
|
std::vector<VkImage> frames;
|
||||||
|
|
||||||
|
SurfaceInfo surfaceInfo;
|
||||||
QueueFamiliesBundle queueFamilies;
|
QueueFamiliesBundle queueFamilies;
|
||||||
QueuesBundle queues;
|
QueuesBundle queues;
|
||||||
const float defaultQueuePriority = 1.0f;
|
const float defaultQueuePriority = 1.0f;
|
||||||
@ -66,6 +83,7 @@ private:
|
|||||||
|
|
||||||
void InitVulkan();
|
void InitVulkan();
|
||||||
void SetupDevice();
|
void SetupDevice();
|
||||||
|
void SetupSwapchain();
|
||||||
|
|
||||||
void Threading();
|
void Threading();
|
||||||
void Loop();
|
void Loop();
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "Renderer.hpp"
|
#include "Renderer.hpp"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include <allocator.hpp>
|
#include <allocator.hpp>
|
||||||
|
#include <algorithm>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ void Renderer::InitVulkan()
|
|||||||
|
|
||||||
void Renderer::SetupDevice()
|
void Renderer::SetupDevice()
|
||||||
{
|
{
|
||||||
// Select physical device and queue families
|
// Find physical devices
|
||||||
VkResult vkResult;
|
VkResult vkResult;
|
||||||
uint32_t devicesCount = 0;
|
uint32_t devicesCount = 0;
|
||||||
vkResult = vkEnumeratePhysicalDevices(vulkan, &devicesCount, nullptr);
|
vkResult = vkEnumeratePhysicalDevices(vulkan, &devicesCount, nullptr);
|
||||||
@ -112,6 +113,7 @@ void Renderer::SetupDevice()
|
|||||||
LOG(INFO, "Found %d Vulkan compatible physical devices.", devices.size());
|
LOG(INFO, "Found %d Vulkan compatible physical devices.", devices.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter and select device
|
||||||
gpu = VK_NULL_HANDLE;
|
gpu = VK_NULL_HANDLE;
|
||||||
VkPhysicalDeviceProperties deviceProperties {};
|
VkPhysicalDeviceProperties deviceProperties {};
|
||||||
VkPhysicalDeviceFeatures deviceFeatures {};
|
VkPhysicalDeviceFeatures deviceFeatures {};
|
||||||
@ -121,6 +123,7 @@ void Renderer::SetupDevice()
|
|||||||
{
|
{
|
||||||
uint32_t priority = 1;
|
uint32_t priority = 1;
|
||||||
|
|
||||||
|
// Check device features and properties
|
||||||
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
||||||
|
|
||||||
if (deviceFeatures.wideLines) enabledFeatures.wideLines = VK_TRUE; else continue;
|
if (deviceFeatures.wideLines) enabledFeatures.wideLines = VK_TRUE; else continue;
|
||||||
@ -128,6 +131,7 @@ void Renderer::SetupDevice()
|
|||||||
|
|
||||||
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
||||||
|
|
||||||
|
// Check queue families
|
||||||
uint32_t queueFamiliesCount = 0;
|
uint32_t queueFamiliesCount = 0;
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(
|
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||||
physicalDevice,
|
physicalDevice,
|
||||||
@ -156,7 +160,7 @@ void Renderer::SetupDevice()
|
|||||||
VkBool32 presentSupport = VK_FALSE;
|
VkBool32 presentSupport = VK_FALSE;
|
||||||
vkResult = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport);
|
vkResult = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport);
|
||||||
if (vkResult != VK_SUCCESS)
|
if (vkResult != VK_SUCCESS)
|
||||||
LOG(WARNING, "Failed to check surface present support. Code: %d", vkResult);
|
LOG(WARNING, "Failed to check surface present support. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName);
|
||||||
if (presentSupport)
|
if (presentSupport)
|
||||||
queueFamiliesBuffer.present = i;
|
queueFamiliesBuffer.present = i;
|
||||||
}
|
}
|
||||||
@ -170,17 +174,86 @@ void Renderer::SetupDevice()
|
|||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check surface info
|
||||||
|
SurfaceInfo surfaceInfoBuffer {};
|
||||||
|
|
||||||
|
uint32_t surfaceFormatsCount = 0;
|
||||||
|
vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||||
|
physicalDevice,
|
||||||
|
surface,
|
||||||
|
&surfaceFormatsCount,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(WARNING, "Failed to get surface formats number. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName);
|
||||||
|
surfaceInfoBuffer.availableFormats.resize(surfaceFormatsCount);
|
||||||
|
vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||||
|
physicalDevice,
|
||||||
|
surface,
|
||||||
|
&surfaceFormatsCount,
|
||||||
|
surfaceInfoBuffer.availableFormats.data()
|
||||||
|
);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(WARNING, "Failed to get surface formats. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName);
|
||||||
|
|
||||||
|
uint32_t presentModesCount = 0;
|
||||||
|
vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
|
physicalDevice,
|
||||||
|
surface,
|
||||||
|
&presentModesCount,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(WARNING, "Failed to get surface present modes number. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName);
|
||||||
|
surfaceInfoBuffer.availablePresentModes.resize(presentModesCount);
|
||||||
|
vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
|
physicalDevice,
|
||||||
|
surface,
|
||||||
|
&surfaceFormatsCount,
|
||||||
|
surfaceInfoBuffer.availablePresentModes.data()
|
||||||
|
);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(WARNING, "Failed to get surface present modes. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName);
|
||||||
|
|
||||||
|
if (
|
||||||
|
surfaceInfoBuffer.availableFormats.empty() ||
|
||||||
|
surfaceInfoBuffer.availablePresentModes.empty()
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Rate and select physical device
|
||||||
if (queueFamiliesBuffer.graphics == queueFamiliesBuffer.present)
|
if (queueFamiliesBuffer.graphics == queueFamiliesBuffer.present)
|
||||||
priority += GPU_GRAPHICS_WITH_PRESENT_PRIORITY;
|
priority += GPU_GRAPHICS_WITH_PRESENT_PRIORITY;
|
||||||
|
|
||||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||||
priority += GPU_DISCRETE_PRIORITY;
|
priority += GPU_DISCRETE_PRIORITY;
|
||||||
|
|
||||||
|
for (VkSurfaceFormatKHR format : surfaceInfoBuffer.availableFormats)
|
||||||
|
{
|
||||||
|
surfaceInfoBuffer.format = format;
|
||||||
|
if (format.format == VK_FORMAT_B8G8R8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
{
|
||||||
|
priority += GPU_B8G8R8_SRGB_PRIORITY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
surfaceInfoBuffer.presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
for (VkPresentModeKHR presentMode : surfaceInfoBuffer.availablePresentModes)
|
||||||
|
{
|
||||||
|
if (presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
|
||||||
|
{
|
||||||
|
surfaceInfoBuffer.presentMode = presentMode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (priority > best_priority)
|
if (priority > best_priority)
|
||||||
{
|
{
|
||||||
best_priority = priority;
|
best_priority = priority;
|
||||||
gpu = physicalDevice;
|
gpu = physicalDevice;
|
||||||
queueFamilies = queueFamiliesBuffer;
|
queueFamilies = queueFamiliesBuffer;
|
||||||
|
surfaceInfo = surfaceInfoBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +285,7 @@ void Renderer::SetupDevice()
|
|||||||
|
|
||||||
// Create logical device
|
// Create logical device
|
||||||
std::vector<const char*> deviceExtensions = {
|
std::vector<const char*> deviceExtensions = {
|
||||||
"VK_KHR_swapchain"
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
VkDeviceCreateInfo deviceInfo = {
|
VkDeviceCreateInfo deviceInfo = {
|
||||||
@ -238,6 +311,64 @@ void Renderer::SetupDevice()
|
|||||||
vkGetDeviceQueue(device, queueFamilies.present, 0, &queues.present);
|
vkGetDeviceQueue(device, queueFamilies.present, 0, &queues.present);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::SetupSwapchain()
|
||||||
|
{
|
||||||
|
VkResult vkResult;
|
||||||
|
vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &surfaceInfo.capabilities);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(CRITICAL, "Failed to get surface capabilities. Code: %d", vkResult);
|
||||||
|
|
||||||
|
int width = 0, height = 0;
|
||||||
|
SDL_Vulkan_GetDrawableSize(window, &width, &height);
|
||||||
|
|
||||||
|
// Clamp extent
|
||||||
|
surfaceInfo.extent.width = (std::max)(
|
||||||
|
surfaceInfo.capabilities.minImageExtent.width,
|
||||||
|
(std::min)(surfaceInfo.capabilities.maxImageExtent.width, static_cast<uint32_t>(width))
|
||||||
|
);
|
||||||
|
surfaceInfo.extent.height = (std::max)(
|
||||||
|
surfaceInfo.capabilities.minImageExtent.height,
|
||||||
|
(std::min)(surfaceInfo.capabilities.maxImageExtent.height, static_cast<uint32_t>(height))
|
||||||
|
);
|
||||||
|
|
||||||
|
uint32_t minImagesCount = surfaceInfo.capabilities.minImageCount + 1;
|
||||||
|
// Clamp min images count
|
||||||
|
if (surfaceInfo.capabilities.maxImageCount > 0 && minImagesCount > surfaceInfo.capabilities.maxImageCount)
|
||||||
|
minImagesCount = surfaceInfo.capabilities.maxImageCount;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR swapchainCreateConfig {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.surface = surface,
|
||||||
|
.minImageCount = minImagesCount,
|
||||||
|
.imageFormat = surfaceInfo.format.format,
|
||||||
|
.imageColorSpace = surfaceInfo.format.colorSpace,
|
||||||
|
.imageExtent = surfaceInfo.extent,
|
||||||
|
.imageArrayLayers = 1,
|
||||||
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
|
.preTransform = surfaceInfo.capabilities.currentTransform,
|
||||||
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
|
.presentMode = surfaceInfo.presentMode,
|
||||||
|
.clipped = VK_TRUE,
|
||||||
|
.oldSwapchain = VK_NULL_HANDLE
|
||||||
|
};
|
||||||
|
|
||||||
|
if (queueFamilies.graphics != queueFamilies.present)
|
||||||
|
{
|
||||||
|
uint32_t queueFamiliesShare[] = {queueFamilies.graphics, queueFamilies.present};
|
||||||
|
swapchainCreateConfig.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
swapchainCreateConfig.queueFamilyIndexCount = 2;
|
||||||
|
swapchainCreateConfig.pQueueFamilyIndices = queueFamiliesShare;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
swapchainCreateConfig.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
vkResult = vkCreateSwapchainKHR(device, &swapchainCreateConfig, nullptr, &swapchain);
|
||||||
|
if (vkResult != VK_SUCCESS)
|
||||||
|
LOG(CRITICAL, "Failed to create swapchain. Code: %d", vkResult);
|
||||||
|
else LOG(INFO, "Swapchain is created");
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::Start()
|
void Renderer::Start()
|
||||||
{
|
{
|
||||||
if (isRunning) throw std::exception("Renderer can be started only once");
|
if (isRunning) throw std::exception("Renderer can be started only once");
|
||||||
@ -256,6 +387,7 @@ void Renderer::Threading()
|
|||||||
|
|
||||||
InitVulkan();
|
InitVulkan();
|
||||||
SetupDevice();
|
SetupDevice();
|
||||||
|
SetupSwapchain();
|
||||||
|
|
||||||
Loop();
|
Loop();
|
||||||
|
|
||||||
@ -318,6 +450,7 @@ void Renderer::Request(RenderCommand::Type type)
|
|||||||
|
|
||||||
void Renderer::Release()
|
void Renderer::Release()
|
||||||
{
|
{
|
||||||
|
vkDestroySwapchainKHR(device, swapchain, nullptr);
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
vkDestroySurfaceKHR(vulkan, surface, nullptr);
|
vkDestroySurfaceKHR(vulkan, surface, nullptr);
|
||||||
vkDestroyInstance(vulkan, nullptr);
|
vkDestroyInstance(vulkan, nullptr);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user