Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "pch.h"
- #define GLFW_INCLUDE_VULKAN
- #include <GLFW/glfw3.h>
- #include <iostream>
- #include <algorithm>
- #include <stdexcept>
- #include <functional>
- #include <cstdlib>
- #include <assert.h>
- #include <optional>
- #include <set>
- struct QueueFamilyIndices
- {
- std::optional<uint32_t> graphicsFamily;
- std::optional<uint32_t> presentFamily;
- bool isComplete()
- {
- return graphicsFamily.has_value() && presentFamily.has_value();
- }
- };
- struct SwapChainSupportDetails
- {
- VkSurfaceCapabilitiesKHR capabilities;
- std::vector<VkSurfaceFormatKHR> formats;
- std::vector<VkPresentModeKHR> presentModes;
- };
- VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pCallback)
- {
- auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
- if(func != nullptr)
- {
- return func(instance, pCreateInfo, pAllocator, pCallback);
- }
- else
- {
- return VK_ERROR_EXTENSION_NOT_PRESENT;
- }
- }
- void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT callback, const VkAllocationCallbacks* pAllocator)
- {
- auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
- if(func != nullptr)
- {
- func(instance, callback, pAllocator);
- }
- }
- class HelloTriangleApplication {
- public:
- void run() {
- initWindow();
- initVulkan();
- mainLoop();
- cleanup();
- }
- private:
- //FUNCTIONS
- //CALLBACK Function
- static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
- VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
- VkDebugUtilsMessageTypeFlagsEXT messageType,
- const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
- void* pUserData)
- {
- std::cerr << "validation layers: " << pCallbackData->pMessage << std::endl;
- return VK_FALSE;
- }
- //INITIALIZERS
- //Initialize glfw and create a window
- void initWindow()
- {
- glfwInit();
- //Not creating a opengl context
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- //Resizability
- glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
- window = glfwCreateWindow(WIDTH, HEIGHT, "ASH", nullptr, nullptr);
- }
- //Initialise Vulkan
- void initVulkan()
- {
- createInstance();
- setupDebugCallBack();
- createSurface();
- pickPhysicalDevice();
- createLogicalDevice();
- createSwapChain();
- createImageViews();
- }
- //Create a Vulkan Instance
- void createInstance()
- {
- if (enableValidationLayers && !checkValidationLayerSupport())
- {
- throw std::runtime_error("Validation layers requested, but not available");
- }
- //Optional but recommended. Provides the driver with additional info
- VkApplicationInfo appInfo = {};
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.pApplicationName = "Ash";
- appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.pEngineName = "No Engine";
- appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.apiVersion = VK_API_VERSION_1_0;
- //Tells the driver what extensions and validation layers we want to use
- VkInstanceCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- createInfo.pApplicationInfo = &appInfo;
- //extensions
- auto extensions = getRequiredExtensions();
- createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
- createInfo.ppEnabledExtensionNames = extensions.data();
- //validation layers
- if (enableValidationLayers)
- {
- createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
- createInfo.ppEnabledLayerNames = validationLayers.data();
- }
- else
- {
- createInfo.enabledLayerCount = 0;
- }
- //Create the instance
- if(vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
- {
- throw std::runtime_error("Failed to create instance!");
- }
- }
- void createLogicalDevice()
- {
- QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
- std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
- std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value()};
- float queuePriority = 1.0f;
- for(uint32_t queueFamily : uniqueQueueFamilies)
- {
- VkDeviceQueueCreateInfo queueCreateInfo = {};
- queueCreateInfo.pQueuePriorities = &queuePriority;
- queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
- queueCreateInfo.queueCount = 1;
- queueCreateInfos.push_back(queueCreateInfo);
- }
- VkPhysicalDeviceFeatures deviceFeatures = {};
- VkDeviceCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- createInfo.pQueueCreateInfos = queueCreateInfos.data();
- createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
- 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.value(), 0, &graphicsQueue);
- vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
- }
- void createSurface()
- {
- if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS)
- {
- throw std::runtime_error("Failed to create window surface!");
- }
- }
- //Validation helper function
- bool checkValidationLayerSupport()
- {
- uint32_t layerCount;
- vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
- std::vector<VkLayerProperties> availableLayers(layerCount);
- vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
- for (auto layerName : validationLayers)
- {
- bool layerFound = false;
- for (const auto& layerProperties : availableLayers)
- {
- if(strcmp(layerName, layerProperties.layerName) == 0)
- {
- layerFound = true;
- break;
- }
- }
- if (!layerFound)
- {
- return false;
- }
- }
- return true;
- }
- //Extensions helper function
- std::vector<const char*> getRequiredExtensions()
- {
- uint32_t glfwExtensionCount = 0;
- const char** glfwExtensions;
- glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
- std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
- if (enableValidationLayers)
- {
- extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
- }
- return extensions;
- }
- QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device)
- {
- QueueFamilyIndices indices;
- uint32_t QFcount = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(device, &QFcount, nullptr);
- std::vector<VkQueueFamilyProperties> QFs(QFcount);
- vkGetPhysicalDeviceQueueFamilyProperties(device, &QFcount, QFs.data());
- int i = 0;
- for (const auto& QF : QFs)
- {
- if (QF.queueCount > 0 && QF.queueFlags & VK_QUEUE_GRAPHICS_BIT)
- {
- indices.graphicsFamily = i;
- }
- VkBool32 presentSupport = false;
- vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
- if (QF.queueCount > 0 && presentSupport)
- {
- indices.presentFamily = i;
- }
- if (indices.isComplete())
- {
- break;
- }
- i++;
- }
- return indices;
- }
- bool isDeviceSuitable(VkPhysicalDevice device)
- {
- QueueFamilyIndices indices = findQueueFamilies(device);
- bool extensionsSupported = checkDeviceExtensionsSupport(device);
- bool swapChainAdequate = false;
- if(extensionsSupported)
- {
- SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
- swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
- }
- return indices.isComplete() && extensionsSupported && swapChainAdequate;
- }
- bool checkDeviceExtensionsSupport(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();
- }
- SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device)
- {
- 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 chooseSwapSurfaceFormats(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;
- }
- }
- //can be expanded by ranking available options
- return availableFormats[0];
- }
- VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes)
- {
- VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR; // Double Buffering V-Sync
- for(const auto& availablePresentMode : availablePresentModes)
- {
- if(availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) // Triple Buffering V-Sync
- {
- return availablePresentMode;
- }
- else if(availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
- {
- bestMode = availablePresentMode;
- }
- }
- return bestMode;
- }
- VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
- {
- if(capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
- {
- return capabilities.currentExtent;
- }
- else
- {
- VkExtent2D actualExtent = {WIDTH, HEIGHT};
- actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
- actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
- return actualExtent;
- }
- }
- void createSwapChain()
- {
- SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
- VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormats(swapChainSupport.formats);
- VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
- VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
- 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 = extent;
- createInfo.imageArrayLayers = 1; // 1 for normal screens, more for stereoscopic 3D
- createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // What operations we want to do with the image
- QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
- uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
- if(indices.graphicsFamily != indices.presentFamily)
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; //Image can be owned by multiple queues
- createInfo.queueFamilyIndexCount = 2;
- createInfo.pQueueFamilyIndices = queueFamilyIndices;
- }
- else
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; //Image is owned by one queue
- createInfo.queueFamilyIndexCount = 0;
- createInfo.pQueueFamilyIndices = nullptr;
- }
- createInfo.preTransform = swapChainSupport.capabilities.currentTransform; // Base transform, change for flips or rotations for entire application
- createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // How to blend the alpha value with other windows applications.
- createInfo.presentMode = presentMode;
- createInfo.clipped = VK_TRUE;
- createInfo.oldSwapchain = VK_NULL_HANDLE; // Only one swapchain will be created in this application
- if(vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain) != VK_SUCCESS)
- {
- throw std::runtime_error("Failed to create swapchain");
- }
- }
- void createImageViews()
- {
- 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 view");
- }
- }
- }
- //Set up debug callbacks
- void setupDebugCallBack()
- {
- if(!enableValidationLayers) return;
- VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
- createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
- createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
- createInfo.pfnUserCallback = &debugCallback;
- createInfo.pUserData = nullptr; //optional
- if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS)
- {
- throw std::runtime_error("failed to set up debug callback!");
- }
- }
- //Picks Graphics Card
- void pickPhysicalDevice()
- {
- 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& dev : devices)
- {
- if(isDeviceSuitable(dev))
- {
- physicalDevice = dev;
- break;
- }
- }
- if (physicalDevice == VK_NULL_HANDLE)
- {
- throw std::runtime_error("failed to find suitable GPU!");
- }
- }
- //UPDATE
- void mainLoop()
- {
- while (!glfwWindowShouldClose(window))
- {
- glfwPollEvents();
- }
- }
- //DELETION/CLEANUP
- void cleanup()
- {
- for (auto imageView : swapChainImageViews)
- {
- vkDestroyImageView(device, imageView, nullptr);
- }
- vkDestroySwapchainKHR(device, swapchain, nullptr);
- vkDestroyDevice(device, nullptr);
- if(enableValidationLayers)
- {
- DestroyDebugUtilsMessengerEXT(instance, callback, nullptr);
- }
- vkDestroySurfaceKHR(instance, surface, nullptr);
- vkDestroyInstance(instance, nullptr);
- glfwDestroyWindow(window);
- glfwTerminate();
- }
- //VARIABLES
- GLFWwindow* window = nullptr;
- const int WIDTH = 2000;
- const int HEIGHT = 1500;
- VkInstance instance;
- VkDebugUtilsMessengerEXT callback;
- VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
- VkDevice device;
- VkQueue graphicsQueue;
- VkQueue presentQueue;
- VkSurfaceKHR surface;
- VkSwapchainKHR swapchain;
- std::vector<VkImageView> swapChainImageViews;
- std::vector<VkImage> swapChainImages;
- VkFormat swapChainImageFormat;
- const std::vector<const char*> validationLayers = { "VK_LAYER_LUNARG_standard_validation" };
- const std::vector<const char*> deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
- #ifdef NDEBUG
- const bool enableValidationLayers = false;
- #else
- const bool enableValidationLayers = true;
- #endif
- };
- int main() {
- HelloTriangleApplication app;
- try
- {
- app.run();
- }
- catch (const std::exception& e)
- {
- std::cerr << e.what() << std::endl;
- return EXIT_FAILURE;
- }
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement