summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward O'Callaghan <funfunctor@folklore1984.net>2017-02-07 22:05:57 +1100
committerEdward O'Callaghan <funfunctor@folklore1984.net>2017-02-07 22:05:57 +1100
commit69fb536dffe9fe6aa4b78921225db9ddc228ba51 (patch)
tree22218e1985ed2c6d1065fb486ac4e4716b5a3b05 /src
parent01ac1b3060a094646d2d5fab32099a8cfffba9e4 (diff)
src/main.cpp: Mostly implemented :/
Signed-off-by: Edward O'Callaghan <funfunctor@folklore1984.net>
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 43416ee..c558af8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,22 +3,451 @@
#include <iostream>
#include <stdexcept>
#include <functional>
+#include <algorithm>
+#include <vector>
+#include <set>
+
+#include "res_mgmr.hcpp"
+#include "shader_loader.hcpp"
+
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
class HelloTriangleApplication {
public:
void run() {
+ initWindow();
initVulkan();
mainLoop();
}
private:
+ const int WIDTH = 800;
+ const int HEIGHT = 600;
+
+ GLFWwindow *window;
+
+ VDeleter<VkInstance> instance {vkDestroyInstance};
+ VDeleter<VkSurfaceKHR> surface{instance, vkDestroySurfaceKHR};
+
+ VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+ VDeleter<VkDevice> device{vkDestroyDevice};
+
+ VkQueue graphicsQueue;
+ VkQueue presentQueue;
+
+ VDeleter<VkSwapchainKHR> swapChain{device, vkDestroySwapchainKHR};
+ std::vector<VkImage> swapChainImages;
+ VkFormat swapChainImageFormat;
+ VkExtent2D swapChainExtent;
+
+ std::vector<VDeleter<VkImageView>> swapChainImageViews;
+
+ struct QueueFamilyIndices {
+ int graphicsFamily = -1;
+ int presentFamily = -1;
+
+ bool isComplete() {
+ return graphicsFamily >= 0 && presentFamily >= 0;
+ }
+ };
+
+ struct SwapChainSupportDetails {
+ VkSurfaceCapabilitiesKHR capabilities;
+ std::vector<VkSurfaceFormatKHR> formats;
+ std::vector<VkPresentModeKHR> presentModes;
+ };
+
+ const std::vector<const char*> deviceExtensions = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME
+ };
+
+ const std::vector<const char*> validationLayers = {
+ "VK_LAYER_LUNARG_standard_validation"
+ };
+//#ifdef NDEBUG
+ const bool enableValidationLayers = false;
+//#else
+// const bool enableValidationLayers = true;
+//#endif
+
+ void initWindow() {
+ glfwInit();
+
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+
+ window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
+ }
+
void initVulkan() {
+ createInstance();
+ createSurface();
+ pickPhysicalDevice();
+ createLogicalDevice();
+ createSwapChain();
+ createImageViews();
+ createGraphicsPipeline();
+ }
+
+ void createGraphicsPipeline() {
+ auto vertShaderCode = readFile("shaders/vert.spv");
+ auto fragShaderCode = readFile("shaders/frag.spv");
+
+ VDeleter<VkShaderModule> vertShaderModule{device, vkDestroyShaderModule};
+ VDeleter<VkShaderModule> fragShaderModule{device, vkDestroyShaderModule};
+ createShaderModule(vertShaderCode, vertShaderModule);
+ createShaderModule(fragShaderCode, fragShaderModule);
+
+ VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
+ vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vertShaderStageInfo.module = vertShaderModule;
+ vertShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
+ fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ fragShaderStageInfo.module = fragShaderModule;
+ fragShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
+ // shaderStages ??
+ }
+
+ void createShaderModule(const std::vector<char>& code, VDeleter<VkShaderModule>& shaderModule) {
+ VkShaderModuleCreateInfo createInfo = {};
+ createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ createInfo.codeSize = code.size();
+ createInfo.pCode = (uint32_t *) code.data();
+
+ if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS)
+ throw std::runtime_error("failed to create shader module!");
+ }
+
+ void createImageViews() {
+ swapChainImageViews.resize(swapChainImages.size(), VDeleter<VkImageView>{device, vkDestroyImageView});
+
+ for (uint32_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].replace()) != VK_SUCCESS)
+ throw std::runtime_error("failed to create image views!");
+ }
+ }
+
+ 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;
+ }
+
+ void createSwapChain() {
+ SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
+
+ VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(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;
+ createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
+ 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.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.replace()) != 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;
+ swapChainExtent = extent;
+ }
+
+ // utils
+
+ 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) {
+ for (const auto& availablePresentMode : availablePresentModes)
+ if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
+ return availablePresentMode;
+
+ return VK_PRESENT_MODE_FIFO_KHR;
+ }
+
+ 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 createSurface() {
+ if (glfwCreateWindowSurface(instance, window, nullptr, surface.replace()) != VK_SUCCESS)
+ throw std::runtime_error("failed to create window surface!");
+ }
+
+ void createLogicalDevice() {
+ QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
+
+ 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.pQueueCreateInfos = queueCreateInfos.data();
+ createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size();
+
+ createInfo.pEnabledFeatures = &deviceFeatures;
+
+ createInfo.enabledExtensionCount = deviceExtensions.size();
+ createInfo.ppEnabledExtensionNames = deviceExtensions.data();
+
+ if (enableValidationLayers) {
+// createInfo.enabledLayerCount = validationLayers.size();
+// createInfo.ppEnabledLayerNames = validationLayers.data();
+ } else {
+ createInfo.enabledLayerCount = 0;
+ }
+
+ if (vkCreateDevice(physicalDevice, &createInfo, nullptr, device.replace()) != VK_SUCCESS)
+ throw std::runtime_error("failed to create logical device!");
+
+ vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);
+ vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);
+ }
+
+ void pickPhysicalDevice() {
+ uint32_t deviceCount = 0;
+
+ vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
+ if (deviceCount == 0)
+ throw std::runtime_error("failed to find GPUs with Vk support!");
+ std::vector<VkPhysicalDevice> devices(deviceCount);
+ vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
+
+ for (const auto& device: devices) {
+ if (isDeviceSuitable(device)) {
+ physicalDevice = device;
+ break;
+ }
+ }
+
+ if (physicalDevice == VK_NULL_HANDLE)
+ throw std::runtime_error("failed to find sutiable GPU!");
+ }
+
+ bool isDeviceSuitable(VkPhysicalDevice device) {
+ QueueFamilyIndices indices = findQueueFamilies(device);
+ bool extensionsSupported = checkDeviceExtensionSupport(device);
+ return indices.isComplete() && extensionsSupported;
+ }
+
+ 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();
+ }
+
+ QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
+ 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) {
+ if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
+ indices.graphicsFamily = i;
+
+ VkBool32 presentSupport = false;
+ vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
+
+ if (queueFamily.queueCount > 0 && presentSupport)
+ indices.presentFamily = i;
+
+ if (indices.isComplete())
+ break;
+
+ i++;
+ }
+
+ return indices;
}
void mainLoop() {
+ while (!glfwWindowShouldClose(window)) {
+ glfwPollEvents();
+ }
+
+ glfwDestroyWindow(window);
+ }
+
+ void createInstance() {
+ VkApplicationInfo appInfo = {};
+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appInfo.pApplicationName = "Learning Vk";
+ appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); // XXX
+ appInfo.pEngineName = "No Engine";
+ appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); // XXX
+ appInfo.apiVersion = VK_API_VERSION_1_0;
+
+ VkInstanceCreateInfo createInfo = {};
+ createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ createInfo.pApplicationInfo = &appInfo;
+
+ unsigned int glfwExtensionCount = 0;
+ const char** glfwExtensions;
+
+ glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
+ createInfo.enabledExtensionCount = glfwExtensionCount;
+ createInfo.ppEnabledExtensionNames = glfwExtensions;
+
+// if (enableValidationLayers && !checkValidationLayerSupprt())
+// throw std::runtime_error("validation layers requested, but not available!");
+
+ if (enableValidationLayers) {
+// createInfo.enabledLayerCount = validationLayers.size();
+// createInfo.ppEnabledLayerNames = validationLayers.data();
+ } else {
+ createInfo.enabledLayerCount = 0;
+ }
+
+ if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS)
+ throw std::runtime_error("failed to create instance!");
+ }
+
+#if 0
+ bool checkValidationLayerSupport() {
+ uint32_t layerCount;
+ vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
+
+ std::vector<VkLayerProperties> availableLayers(layerCount);
+ vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
+
+ for (const char* layerName : validationLayers) {
+ bool layerFound = false;
+
+ for (const auto& layerProperties : availableLayers) {
+ if (strcmp(layerName, layerProperties.layerName) == 0) {
+ layerFound = true;
+ break;
+ }
+ }
+
+ if (!layerFound)
+ return false;
+ }
+ return false;
}
+#endif
};
int main() {