vulkan device updated
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
|
||||
|
||||
@@ -60,7 +61,7 @@ namespace wiGraphicsTypes
|
||||
void* userData) {
|
||||
|
||||
std::stringstream ss("");
|
||||
ss << "validation layer: " << msg << std::endl;
|
||||
ss << "[VULKAN validation layer]: " << msg << std::endl;
|
||||
|
||||
std::cerr << ss.str();
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
@@ -83,6 +84,137 @@ namespace wiGraphicsTypes
|
||||
}
|
||||
}
|
||||
|
||||
// Queue families:
|
||||
struct QueueFamilyIndices {
|
||||
int graphicsFamily = -1;
|
||||
int presentFamily = -1;
|
||||
|
||||
bool isComplete() {
|
||||
return graphicsFamily >= 0 && presentFamily >= 0;
|
||||
}
|
||||
};
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
||||
QueueFamilyIndices indices;
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& queueFamily : queueFamilies) {
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
||||
if (queueFamily.queueCount > 0 && presentSupport) {
|
||||
indices.presentFamily = i;
|
||||
}
|
||||
|
||||
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
indices.graphicsFamily = i;
|
||||
}
|
||||
|
||||
if (indices.isComplete()) {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
// Swapchain helpers:
|
||||
const std::vector<const char*> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
|
||||
|
||||
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
||||
|
||||
for (const auto& extension : availableExtensions) {
|
||||
requiredExtensions.erase(extension.extensionName);
|
||||
}
|
||||
|
||||
return requiredExtensions.empty();
|
||||
}
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
};
|
||||
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
||||
SwapChainSupportDetails details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
||||
|
||||
if (formatCount != 0) {
|
||||
details.formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
|
||||
|
||||
if (presentModeCount != 0) {
|
||||
details.presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
|
||||
if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) {
|
||||
return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
}
|
||||
|
||||
for (const auto& availableFormat : availableFormats) {
|
||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
return availableFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return availableFormats[0];
|
||||
}
|
||||
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {
|
||||
VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
|
||||
for (const auto& availablePresentMode : availablePresentModes) {
|
||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
return availablePresentMode;
|
||||
}
|
||||
else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
|
||||
bestMode = availablePresentMode;
|
||||
}
|
||||
}
|
||||
|
||||
return bestMode;
|
||||
}
|
||||
|
||||
// Device selection helpers:
|
||||
bool isDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
||||
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
||||
|
||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||
|
||||
bool swapChainAdequate = false;
|
||||
if (extensionsSupported) {
|
||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device, surface);
|
||||
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
|
||||
}
|
||||
|
||||
return indices.isComplete() && extensionsSupported && swapChainAdequate;
|
||||
}
|
||||
|
||||
|
||||
// Engine functions
|
||||
GraphicsDevice_Vulkan::GraphicsDevice_Vulkan(wiWindowRegistration::window_type window, bool fullscreen) : GraphicsDevice()
|
||||
@@ -121,19 +253,21 @@ namespace wiGraphicsTypes
|
||||
}
|
||||
|
||||
// Create instance:
|
||||
VkInstanceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensionNames.data();
|
||||
createInfo.enabledLayerCount = 0;
|
||||
if (enableValidationLayers)
|
||||
{
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
}
|
||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create instance!");
|
||||
VkInstanceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensionNames.data();
|
||||
createInfo.enabledLayerCount = 0;
|
||||
if (enableValidationLayers)
|
||||
{
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
}
|
||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create instance!");
|
||||
}
|
||||
}
|
||||
|
||||
// Register validation layer callback:
|
||||
@@ -149,9 +283,182 @@ namespace wiGraphicsTypes
|
||||
}
|
||||
|
||||
|
||||
// Surface creation:
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VkWin32SurfaceCreateInfoKHR createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.hwnd = window;
|
||||
createInfo.hinstance = GetModuleHandle(nullptr);
|
||||
|
||||
auto CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
|
||||
|
||||
if (!CreateWin32SurfaceKHR || CreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create window surface!");
|
||||
}
|
||||
#else
|
||||
#error WICKEDENGINE VULKAN DEVICE ERROR: PLATFORM NOT SUPPORTED
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
|
||||
// Enumerating and creating devices:
|
||||
{
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
|
||||
if (deviceCount == 0) {
|
||||
throw std::runtime_error("failed to find GPUs with Vulkan support!");
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
|
||||
for (const auto& device : devices) {
|
||||
if (isDeviceSuitable(device, surface)) {
|
||||
physicalDevice = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (physicalDevice == VK_NULL_HANDLE) {
|
||||
throw std::runtime_error("failed to find a suitable GPU!");
|
||||
}
|
||||
|
||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
std::set<int> uniqueQueueFamilies = { indices.graphicsFamily, indices.presentFamily };
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
for (int queueFamily : uniqueQueueFamilies) {
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures = {};
|
||||
|
||||
VkDeviceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
|
||||
if (enableValidationLayers) {
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
}
|
||||
else {
|
||||
createInfo.enabledLayerCount = 0;
|
||||
}
|
||||
|
||||
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create logical device!");
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);
|
||||
vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);
|
||||
}
|
||||
|
||||
// Set up swap chain:
|
||||
{
|
||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice, surface);
|
||||
|
||||
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
|
||||
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
|
||||
|
||||
swapChainExtent = { static_cast<uint32_t>(SCREENWIDTH), static_cast<uint32_t>(SCREENHEIGHT) };
|
||||
swapChainExtent.width = max(swapChainSupport.capabilities.minImageExtent.width, min(swapChainSupport.capabilities.maxImageExtent.width, swapChainExtent.width));
|
||||
swapChainExtent.height = max(swapChainSupport.capabilities.minImageExtent.height, min(swapChainSupport.capabilities.maxImageExtent.height, swapChainExtent.height));
|
||||
|
||||
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
|
||||
if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
|
||||
imageCount = swapChainSupport.capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
createInfo.surface = surface;
|
||||
createInfo.minImageCount = imageCount;
|
||||
createInfo.imageFormat = surfaceFormat.format;
|
||||
createInfo.imageColorSpace = surfaceFormat.colorSpace;
|
||||
createInfo.imageExtent = swapChainExtent;
|
||||
createInfo.imageArrayLayers = 1;
|
||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||
uint32_t queueFamilyIndices[] = { (uint32_t)indices.graphicsFamily, (uint32_t)indices.presentFamily };
|
||||
|
||||
if (indices.graphicsFamily != indices.presentFamily) {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
createInfo.queueFamilyIndexCount = 2;
|
||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||
}
|
||||
else {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.queueFamilyIndexCount = 0; // Optional
|
||||
createInfo.pQueueFamilyIndices = nullptr; // Optional
|
||||
}
|
||||
|
||||
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
|
||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
createInfo.presentMode = presentMode;
|
||||
createInfo.clipped = VK_TRUE;
|
||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create swap chain!");
|
||||
}
|
||||
|
||||
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
|
||||
swapChainImages.resize(imageCount);
|
||||
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
|
||||
|
||||
swapChainImageFormat = surfaceFormat.format;
|
||||
|
||||
|
||||
swapChainImageViews.resize(swapChainImages.size());
|
||||
for (size_t i = 0; i < swapChainImages.size(); i++)
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = swapChainImages[i];
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.format = swapChainImageFormat;
|
||||
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createInfo.subresourceRange.baseMipLevel = 0;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image views!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
GraphicsDevice_Vulkan::~GraphicsDevice_Vulkan()
|
||||
{
|
||||
for (auto imageView : swapChainImageViews) {
|
||||
vkDestroyImageView(device, imageView, nullptr);
|
||||
}
|
||||
vkDestroySwapchainKHR(device, swapChain, nullptr);
|
||||
vkDestroyDevice(device, nullptr);
|
||||
DestroyDebugReportCallbackEXT(instance, callback, nullptr);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#include "wiGraphicsDevice.h"
|
||||
#include "wiWindowRegistration.h"
|
||||
|
||||
|
||||
#ifdef WICKEDENGINE_BUILD_VULKAN
|
||||
#include "Include_Vulkan.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace wiGraphicsTypes
|
||||
{
|
||||
|
||||
@@ -18,6 +19,17 @@ namespace wiGraphicsTypes
|
||||
|
||||
VkInstance instance;
|
||||
VkDebugReportCallbackEXT callback;
|
||||
VkSurfaceKHR surface;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice device;
|
||||
VkQueue graphicsQueue;
|
||||
VkQueue presentQueue;
|
||||
|
||||
VkSwapchainKHR swapChain;
|
||||
std::vector<VkImage> swapChainImages;
|
||||
std::vector<VkImageView> swapChainImageViews;
|
||||
VkFormat swapChainImageFormat;
|
||||
VkExtent2D swapChainExtent;
|
||||
|
||||
public:
|
||||
GraphicsDevice_Vulkan(wiWindowRegistration::window_type window, bool fullscreen = false);
|
||||
|
||||
Reference in New Issue
Block a user