From dcf2a5ab1047e1ba114d45a245d4b5fd52db2d05 Mon Sep 17 00:00:00 2001 From: AliMehrabani Date: Wed, 30 Oct 2024 11:23:26 +0330 Subject: [PATCH] Push files to the new remote --- .gitignore | 2 + .qmake.stash | 29 ++ HelloTriangleApplication.cpp | 266 ++++++------ HelloTriangleApplication.h | 37 +- VkDescriptors.cpp | 6 + VkDescriptors.h | 12 + VkEngine.cpp | 402 ++++++++++++++++++ VkEngine.h | 110 +++++ VkImages.cpp | 34 ++ VkImages.h | 22 + VkInitializers.cpp | 342 +++++++++++++++ VkInitializers.h | 62 +++ VkLoader.cpp | 6 + VkLoader.h | 12 + VkMain.cpp | 17 + VkMain.h | 15 + VkPipelines.cpp | 6 + VkPipelines.h | 12 + VkTest.pro | 46 +- VkTest.pro.user | 7 +- VkTypes.h | 41 ++ android-libVkTest.so-deployment-settings.json | 17 + main.cpp | 9 +- 23 files changed, 1349 insertions(+), 163 deletions(-) create mode 100644 .qmake.stash create mode 100644 VkDescriptors.cpp create mode 100644 VkDescriptors.h create mode 100644 VkEngine.cpp create mode 100644 VkEngine.h create mode 100644 VkImages.cpp create mode 100644 VkImages.h create mode 100644 VkInitializers.cpp create mode 100644 VkInitializers.h create mode 100644 VkLoader.cpp create mode 100644 VkLoader.h create mode 100644 VkMain.cpp create mode 100644 VkMain.h create mode 100644 VkPipelines.cpp create mode 100644 VkPipelines.h create mode 100644 VkTypes.h create mode 100644 android-libVkTest.so-deployment-settings.json diff --git a/.gitignore b/.gitignore index 67bcc2f..71ea0ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .gradle/ build/ +third_party/ +glm/ diff --git a/.qmake.stash b/.qmake.stash new file mode 100644 index 0000000..198e39b --- /dev/null +++ b/.qmake.stash @@ -0,0 +1,29 @@ +QMAKE_CXX.QT_COMPILER_STDCXX = 201402L +QMAKE_CXX.QMAKE_CLANG_MAJOR_VERSION = 8 +QMAKE_CXX.QMAKE_CLANG_MINOR_VERSION = 0 +QMAKE_CXX.QMAKE_CLANG_PATCH_VERSION = 7 +QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 4 +QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2 +QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 1 +QMAKE_CXX.COMPILER_MACROS = \ + QT_COMPILER_STDCXX \ + QMAKE_CLANG_MAJOR_VERSION \ + QMAKE_CLANG_MINOR_VERSION \ + QMAKE_CLANG_PATCH_VERSION \ + QMAKE_GCC_MAJOR_VERSION \ + QMAKE_GCC_MINOR_VERSION \ + QMAKE_GCC_PATCH_VERSION +QMAKE_CXX.INCDIRS = \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sysroot/usr/include/aarch64-linux-android \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++/include \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/android/support/include \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++abi/include \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7/include \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sysroot/usr/include +QMAKE_CXX.LIBDIRS = \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7 \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7/lib/linux/aarch64 \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/lib/gcc/aarch64-linux-android/4.9.x \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/aarch64-linux-android/lib64 \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/aarch64-linux-android/lib \ + /home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/platforms/android-21/arch-arm64/usr/lib diff --git a/HelloTriangleApplication.cpp b/HelloTriangleApplication.cpp index a54b2a1..ae27996 100644 --- a/HelloTriangleApplication.cpp +++ b/HelloTriangleApplication.cpp @@ -52,18 +52,18 @@ void HelloTriangleApplication::run() void HelloTriangleApplication::initWindow() { - glfwInit(); +// glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +// glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - _window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); - glfwSetWindowUserPointer(_window, this); - glfwSetFramebufferSizeCallback(_window, framebufferResizeCallback); +// _window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); +// glfwSetWindowUserPointer(_window, this); +// glfwSetFramebufferSizeCallback(_window, framebufferResizeCallback); } -void HelloTriangleApplication::framebufferResizeCallback(GLFWwindow* window, int /*width*/, int /*height*/) { - auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); - app->framebufferResized = true; +void HelloTriangleApplication::framebufferResizeCallback(QQuickWindow* window, int /*width*/, int /*height*/) { +// auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); +// app->framebufferResized = true; } @@ -95,6 +95,32 @@ void HelloTriangleApplication::initVulkan() createSyncObjects(); } +bool HelloTriangleApplication::checkValidationLayerSupport() +{ + uint32_t layerCount; + vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + + std::vector 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 true; +} + void HelloTriangleApplication::createInstance() { VkApplicationInfo appInfo{}; @@ -133,51 +159,11 @@ void HelloTriangleApplication::createInstance() } -void HelloTriangleApplication::setupDebugMessenger() { - if (!enableValidationLayers) - { - return; - } - - VkDebugUtilsMessengerCreateInfoEXT createInfo{}; - populateDebugMessengerCreateInfo(createInfo); - - if (CreateDebugUtilsMessengerEXT(_instance, &createInfo, nullptr, &_debugMessenger) != VK_SUCCESS) { - throw std::runtime_error("failed to set up debug messenger!"); - } -} - -bool HelloTriangleApplication::checkValidationLayerSupport() -{ - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - - std::vector 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 true; -} - std::vector HelloTriangleApplication::getRequiredExtensions() { uint32_t glfwExtensionCount = 0; const char** glfwExtensions; - glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); +// glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); @@ -188,6 +174,20 @@ std::vector HelloTriangleApplication::getRequiredExtensions() return extensions; } +void HelloTriangleApplication::setupDebugMessenger() { + if (!enableValidationLayers) + { + return; + } + + VkDebugUtilsMessengerCreateInfoEXT createInfo{}; + populateDebugMessengerCreateInfo(createInfo); + + if (CreateDebugUtilsMessengerEXT(_instance, &createInfo, nullptr, &_debugMessenger) != VK_SUCCESS) { + throw std::runtime_error("failed to set up debug messenger!"); + } +} + void HelloTriangleApplication::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) { createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; @@ -203,9 +203,9 @@ void HelloTriangleApplication::populateDebugMessengerCreateInfo(VkDebugUtilsMess void HelloTriangleApplication::createSurface() { - if (glfwCreateWindowSurface(_instance, _window, nullptr, &_surface) != VK_SUCCESS) { - throw std::runtime_error("failed to create window surface!"); - } +// if (glfwCreateWindowSurface(_instance, _window, nullptr, &_surface) != VK_SUCCESS) { +// throw std::runtime_error("failed to create window surface!"); +// } } void HelloTriangleApplication::pickPhysicalDevice() { @@ -254,49 +254,44 @@ bool HelloTriangleApplication::isDeviceSuitable(VkPhysicalDevice device) { return indices.isComplete() && extensionsSupported && swapChainAdequate; } -void HelloTriangleApplication::createLogicalDevice() -{ - QueueFamilyIndices indices = findQueueFamilies(_physicalDevice); +bool HelloTriangleApplication::checkDeviceExtensionSupport(VkPhysicalDevice device) { + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - std::vector queueCreateInfos; - std::set uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()}; + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); - float queuePriority = 1.0f; - for (uint32_t 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); - } + std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - VkPhysicalDeviceFeatures deviceFeatures{}; + for (const auto& extension : availableExtensions) { + requiredExtensions.erase(extension.extensionName); + } - VkDeviceCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + return requiredExtensions.empty(); +} - createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); - createInfo.pQueueCreateInfos = queueCreateInfos.data(); +SwapChainSupportDetails HelloTriangleApplication::querySwapChainSupport(VkPhysicalDevice device) { + SwapChainSupportDetails details; - createInfo.pEnabledFeatures = &deviceFeatures; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, _surface, &details.capabilities); - createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &formatCount, nullptr); - if (enableValidationLayers) { - createInfo.enabledLayerCount = static_cast(validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - } else { - createInfo.enabledLayerCount = 0; + if (formatCount != 0) { + details.formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &formatCount, details.formats.data()); } - if (vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device) != VK_SUCCESS) { - throw std::runtime_error("failed to create logical device!"); + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, _surface, &presentModeCount, nullptr); + + if (presentModeCount != 0) { + details.presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, _surface, &presentModeCount, details.presentModes.data()); } - vkGetDeviceQueue(_device, indices.graphicsFamily.value(), 0, &_graphicsQueue); - vkGetDeviceQueue(_device, indices.presentFamily.value(), 0, &_presentQueue); + return details; } QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice device) { @@ -331,6 +326,51 @@ QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice return indices; } +void HelloTriangleApplication::createLogicalDevice() +{ + QueueFamilyIndices indices = findQueueFamilies(_physicalDevice); + + std::vector queueCreateInfos; + std::set uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()}; + + float queuePriority = 1.0f; + for (uint32_t 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(queueCreateInfos.size()); + createInfo.pQueueCreateInfos = queueCreateInfos.data(); + + createInfo.pEnabledFeatures = &deviceFeatures; + + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); + createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + + if (enableValidationLayers) { + createInfo.enabledLayerCount = static_cast(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 HelloTriangleApplication::createSwapChain() { SwapChainSupportDetails swapChainSupport = querySwapChainSupport(_physicalDevice); @@ -385,22 +425,6 @@ void HelloTriangleApplication::createSwapChain() { _swapChainExtent = extent; } -bool HelloTriangleApplication::checkDeviceExtensionSupport(VkPhysicalDevice device) { - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); - - std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - - for (const auto& extension : availableExtensions) { - requiredExtensions.erase(extension.extensionName); - } - - return requiredExtensions.empty(); -} - VkSurfaceFormatKHR HelloTriangleApplication::chooseSwapSurfaceFormat(const std::vector& availableFormats) { for (const auto& availableFormat : availableFormats) { if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { @@ -426,7 +450,7 @@ VkExtent2D HelloTriangleApplication::chooseSwapExtent(const VkSurfaceCapabilitie return capabilities.currentExtent; } else { int width, height; - glfwGetFramebufferSize(_window, &width, &height); +// glfwGetFramebufferSize(_window, &width, &height); VkExtent2D actualExtent = { static_cast(width), @@ -440,30 +464,6 @@ VkExtent2D HelloTriangleApplication::chooseSwapExtent(const VkSurfaceCapabilitie } } -SwapChainSupportDetails HelloTriangleApplication::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 HelloTriangleApplication::createImageViews() { _swapChainImageViews.resize(_swapChainImages.size()); for (size_t i = 0; i < _swapChainImages.size(); i++) { @@ -1017,10 +1017,10 @@ void HelloTriangleApplication::createSyncObjects() { void HelloTriangleApplication::mainLoop() { - while (!glfwWindowShouldClose(_window)) { - glfwPollEvents(); - drawFrame(); - } +// while (!glfwWindowShouldClose(_window)) { +// glfwPollEvents(); +// drawFrame(); +// } vkDeviceWaitIdle(_device); } @@ -1107,10 +1107,10 @@ void HelloTriangleApplication::updateUniformBuffer(uint32_t currentImage) { void HelloTriangleApplication::recreateSwapChain() { int width = 0, height = 0; - glfwGetFramebufferSize(_window, &width, &height); +// glfwGetFramebufferSize(_window, &width, &height); while (width == 0 || height == 0) { - glfwGetFramebufferSize(_window, &width, &height); - glfwWaitEvents(); +// glfwGetFramebufferSize(_window, &width, &height); +// glfwWaitEvents(); } vkDeviceWaitIdle(_device); @@ -1177,7 +1177,7 @@ void HelloTriangleApplication::cleanup() vkDestroyInstance(_instance, nullptr); - glfwDestroyWindow(_window); +// glfwDestroyWindow(_window); - glfwTerminate(); +// glfwTerminate(); } diff --git a/HelloTriangleApplication.h b/HelloTriangleApplication.h index e210d57..05c79b0 100644 --- a/HelloTriangleApplication.h +++ b/HelloTriangleApplication.h @@ -7,21 +7,23 @@ const bool enableValidationLayers = true; #endif -//#include +#include -#define VK_USE_PLATFORM_ -#define GLFW_INCLUDE_VULKAN -#include -#define GLFW_EXPOSE_NATIVE_ -#include +//#define VK_USE_PLATFORM_ +//#define GLFW_INCLUDE_VULKAN +//#include +//#define GLFW_EXPOSE_NATIVE_ +//#include #define GLM_FORCE_RADIANS +#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES #include #include #include #include +#include #include #include #include // Necessary for uint32_t @@ -30,6 +32,12 @@ #include #include +#ifdef Q_OS_ANDROID + const QString TARGET_PLATFORM = "Android"; +#else + const QString TARGET_PLATFORM = "Linux"; +#endif + const int MAX_FRAMES_IN_FLIGHT = 2; struct QueueFamilyIndices { @@ -48,8 +56,8 @@ struct SwapChainSupportDetails { }; struct Vertex { - glm::vec2 pos; - glm::vec3 color; + alignas(16) glm::vec2 pos; + alignas(16) glm::vec3 color; static VkVertexInputBindingDescription getBindingDescription() { VkVertexInputBindingDescription bindingDescription{}; @@ -78,9 +86,9 @@ struct Vertex { }; struct UniformBufferObject { - glm::mat4 model; - glm::mat4 view; - glm::mat4 proj; + alignas(16) glm::mat4 model; + alignas(16) glm::mat4 view; + alignas(16) glm::mat4 proj; }; class HelloTriangleApplication @@ -98,7 +106,9 @@ public: return VK_FALSE; } static std::vector readFile(const std::string& filename); - static void framebufferResizeCallback(GLFWwindow* window, int width, int height); + +// static void framebufferResizeCallback(GLFWwindow* window, int width, int height); + static void framebufferResizeCallback(QQuickWindow* window, int width, int height); private: void initWindow(); @@ -180,7 +190,8 @@ private: uint32_t currentFrame = 0; bool framebufferResized = false; - GLFWwindow *_window; +// GLFWwindow *_window; + QQuickWindow* _window; VkInstance _instance; VkDebugUtilsMessengerEXT _debugMessenger; VkPhysicalDevice _physicalDevice; diff --git a/VkDescriptors.cpp b/VkDescriptors.cpp new file mode 100644 index 0000000..41dd2ce --- /dev/null +++ b/VkDescriptors.cpp @@ -0,0 +1,6 @@ +#include "VkDescriptors.h" + +VkDescriptors::VkDescriptors() +{ + +} diff --git a/VkDescriptors.h b/VkDescriptors.h new file mode 100644 index 0000000..2234184 --- /dev/null +++ b/VkDescriptors.h @@ -0,0 +1,12 @@ +#ifndef VKDESCRIPTORS_H +#define VKDESCRIPTORS_H + +#include + +class VkDescriptors +{ +public: + VkDescriptors(); +}; + +#endif // VKDESCRIPTORS_H diff --git a/VkEngine.cpp b/VkEngine.cpp new file mode 100644 index 0000000..11082be --- /dev/null +++ b/VkEngine.cpp @@ -0,0 +1,402 @@ +#include "VkEngine.h" + +#include +#include + +#include +#include + +//bootstrap library +#include "VkBootstrap.h" +#include "VkImages.h" + +#define VMA_IMPLEMENTATION +#include "vma/vk_mem_alloc.h" + +#include +#include +//< includes + +//> init +constexpr bool bUseValidationLayers = false; + +VkEngine* loadedEngine = nullptr; + +VkEngine::VkEngine() +{ + +} + +VkEngine& VkEngine::Get() +{ + return *loadedEngine; +} + +void VkEngine::init() +{ + // only one engine initialization is allowed with the application. + assert(loadedEngine == nullptr); + loadedEngine = this; + + // We initialize SDL and create a window with it. + SDL_Init(SDL_INIT_VIDEO); + + SDL_WindowFlags window_flags = static_cast(SDL_WINDOW_VULKAN); + + _window = SDL_CreateWindow( + "Vulkan Engine", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + _windowExtent.width, + _windowExtent.height, + window_flags); + + init_vulkan(); + + init_swapchain(); + + init_commands(); + + init_sync_structures(); + + // everything went fine + _isInitialized = true; +} + +void VkEngine::cleanup() +{ + if (_isInitialized) { + + vkDeviceWaitIdle(_device); + + for (int i = 0; i < static_cast(FRAME_OVERLAP); i++) + { + //already written from before + vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr); + + //destroy sync objects + vkDestroyFence(_device, _frames[i]._renderFence, nullptr); + vkDestroySemaphore(_device, _frames[i]._renderSemaphore, nullptr); + vkDestroySemaphore(_device ,_frames[i]._swapchainSemaphore, nullptr); + + _frames[i]._deletionQueue.flush(); + } + + _mainDeletionQueue.flush(); + + vkDeviceWaitIdle(_device); + + for (int i = 0; i < static_cast(FRAME_OVERLAP); i++) { + vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr); + } + + destroy_swapchain(); + + vkDestroySurfaceKHR(_instance, _surface, nullptr); + vkDestroyDevice(_device, nullptr); + + vkb::destroy_debug_utils_messenger(_instance, _debug_messenger); + vkDestroyInstance(_instance, nullptr); + SDL_DestroyWindow(_window); + } + + // clear engine pointer + loadedEngine = nullptr; +} + +void VkEngine::draw() +{ + // wait until the gpu has finished rendering the last frame. Timeout of 1 + // second + VK_CHECK(vkWaitForFences(_device, 1, &get_current_frame()._renderFence, true, 1000000000)); + + get_current_frame()._deletionQueue.flush(); + + VK_CHECK(vkResetFences(_device, 1, &get_current_frame()._renderFence)); + + uint32_t swapchainImageIndex; + VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, 1000000000, get_current_frame()._swapchainSemaphore, nullptr, &swapchainImageIndex)); + + //naming it cmd for shorter writing + VkCommandBuffer cmd = get_current_frame()._mainCommandBuffer; + + // now that we are sure that the commands finished executing, we can safely + // reset the command buffer to begin recording again. + VK_CHECK(vkResetCommandBuffer(cmd, 0)); + + //begin the command buffer recording. We will use this command buffer exactly once, so we want to let vulkan know that + VkCommandBufferBeginInfo cmdBeginInfo = vkinit::command_buffer_begin_info(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + + //start the command buffer recording + VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo)); + + //make the swapchain image into writeable mode before rendering + vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + + //make a clear-color from frame number. This will flash with a 120 frame period. + VkClearColorValue clearValue; + float flash = std::abs(std::sin(_frameNumber / 120.f)); + clearValue = { { 0.0f, 0.0f, flash, 1.0f } }; + + VkImageSubresourceRange clearRange = vkinit::image_subresource_range(VK_IMAGE_ASPECT_COLOR_BIT); + + //clear image + vkCmdClearColorImage(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange); + + //make the swapchain image into presentable mode + vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex],VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + //finalize the command buffer (we can no longer add commands, but it can now be executed) + VK_CHECK(vkEndCommandBuffer(cmd)); + + //prepare the submission to the queue. + //we want to wait on the _presentSemaphore, as that semaphore is signaled when the swapchain is ready + //we will signal the _renderSemaphore, to signal that rendering has finished + + VkCommandBufferSubmitInfo cmdinfo = vkinit::command_buffer_submit_info(cmd); + + VkSemaphoreSubmitInfo waitInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR,get_current_frame()._swapchainSemaphore); + VkSemaphoreSubmitInfo signalInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, get_current_frame()._renderSemaphore); + + VkSubmitInfo2 submit = vkinit::submit_info(&cmdinfo,&signalInfo,&waitInfo); + + //submit command buffer to the queue and execute it. + // _renderFence will now block until the graphic commands finish execution + VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, get_current_frame()._renderFence)); + + //prepare present + // this will put the image we just rendered to into the visible window. + // we want to wait on the _renderSemaphore for that, + // as its necessary that drawing commands have finished before the image is displayed to the user + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.pNext = nullptr; + presentInfo.pSwapchains = &_swapchain; + presentInfo.swapchainCount = 1; + + presentInfo.pWaitSemaphores = &get_current_frame()._renderSemaphore; + presentInfo.waitSemaphoreCount = 1; + + presentInfo.pImageIndices = &swapchainImageIndex; + + VK_CHECK(vkQueuePresentKHR(_graphicsQueue, &presentInfo)); + + //increase the number of frames drawn + _frameNumber++; +} +//< extras + +//> drawloop +void VkEngine::run() +{ + SDL_Event e; + bool bQuit = false; + + // main loop + while (!bQuit) { + // Handle events on queue + while (SDL_PollEvent(&e) != 0) { + // close the window when user alt-f4s or clicks the X button + if (e.type == SDL_QUIT) + bQuit = true; + + if (e.type == SDL_WINDOWEVENT) { + if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) { + stop_rendering = true; + } + if (e.window.event == SDL_WINDOWEVENT_RESTORED) { + stop_rendering = false; + } + } + } + + // do not draw if we are minimized + if (stop_rendering) { + // throttle the speed to avoid the endless spinning + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + continue; + } + + draw(); + } +} + +void VkEngine::init_vulkan() +{ + vkb::InstanceBuilder builder; + + //make the vulkan instance, with basic debug features + auto inst_ret = builder.set_app_name("Example Vulkan Application") + .request_validation_layers(bUseValidationLayers) + .use_default_debug_messenger() + .require_api_version(1, 3, 0) + .build(); + + vkb::Instance vkb_inst = inst_ret.value(); + + //grab the instance + _instance = vkb_inst.instance; + _debug_messenger = vkb_inst.debug_messenger; + + SDL_Vulkan_CreateSurface(_window, _instance, &_surface); + + //vulkan 1.3 features + VkPhysicalDeviceVulkan13Features features{}; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; + features.dynamicRendering = true; + features.synchronization2 = true; + + //vulkan 1.2 features + VkPhysicalDeviceVulkan12Features features12{}; + features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + features12.bufferDeviceAddress = true; + features12.descriptorIndexing = true; + + + //use vkbootstrap to select a gpu. + //We want a gpu that can write to the SDL surface and supports vulkan 1.3 with the correct features + vkb::PhysicalDeviceSelector selector{ vkb_inst }; + vkb::PhysicalDevice physicalDevice = selector + .set_minimum_version(1, 3) + .set_required_features_13(features) + .set_required_features_12(features12) + .set_surface(_surface) + .select() + .value(); + + + //create the final vulkan device + vkb::DeviceBuilder deviceBuilder{ physicalDevice }; + + vkb::Device vkbDevice = deviceBuilder.build().value(); + + // Get the VkDevice handle used in the rest of a vulkan application + _device = vkbDevice.device; + _chosenGPU = physicalDevice.physical_device; + + _graphicsQueue = vkbDevice.get_queue(vkb::QueueType::graphics).value(); + _graphicsQueueFamily = vkbDevice.get_queue_index(vkb::QueueType::graphics).value(); + + // initialize the memory allocator + VmaAllocatorCreateInfo allocatorInfo = {}; + allocatorInfo.physicalDevice = _chosenGPU; + allocatorInfo.device = _device; + allocatorInfo.instance = _instance; + allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; + vmaCreateAllocator(&allocatorInfo, &_allocator); + + _mainDeletionQueue.push_function([&]() { + vmaDestroyAllocator(_allocator); + }); + +} + +void VkEngine::create_swapchain(uint32_t width, uint32_t height) +{ + vkb::SwapchainBuilder swapchainBuilder{ _chosenGPU,_device,_surface }; + + _swapchainImageFormat = VK_FORMAT_B8G8R8A8_UNORM; + + vkb::Swapchain vkbSwapchain = swapchainBuilder + //.use_default_format_selection() + .set_desired_format(VkSurfaceFormatKHR{ .format = _swapchainImageFormat, .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }) + //use vsync present mode + .set_desired_present_mode(VK_PRESENT_MODE_FIFO_KHR) + .set_desired_extent(width, height) + .add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .build() + .value(); + + _swapchainExtent = vkbSwapchain.extent; + //store swapchain and its related images + _swapchain = vkbSwapchain.swapchain; + _swapchainImages = vkbSwapchain.get_images().value(); + _swapchainImageViews = vkbSwapchain.get_image_views().value(); +} + +void VkEngine::destroy_swapchain() +{ + vkDestroySwapchainKHR(_device, _swapchain, nullptr); + + // destroy swapchain resources + for (int i = 0; i < static_cast(_swapchainImageViews.size()); i++) { + + vkDestroyImageView(_device, _swapchainImageViews[i], nullptr); + } +} + +void VkEngine::init_swapchain() +{ + create_swapchain(_windowExtent.width, _windowExtent.height); + + //draw image size will match the window + VkExtent3D drawImageExtent = { + _windowExtent.width, + _windowExtent.height, + 1 + }; + + //hardcoding the draw format to 32 bit float + _drawImage.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + _drawImage.imageExtent = drawImageExtent; + + VkImageUsageFlags drawImageUsages{}; + drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + drawImageUsages |= VK_IMAGE_USAGE_STORAGE_BIT; + drawImageUsages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + VkImageCreateInfo rimg_info = vkinit::image_create_info(_drawImage.imageFormat, drawImageUsages, drawImageExtent); + + //for the draw image, we want to allocate it from gpu local memory + VmaAllocationCreateInfo rimg_allocinfo = {}; + rimg_allocinfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + rimg_allocinfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + //allocate and create the image + vmaCreateImage(_allocator, &rimg_info, &rimg_allocinfo, &_drawImage.image, &_drawImage.allocation, nullptr); + + //build a image-view for the draw image to use for rendering + VkImageViewCreateInfo rview_info = vkinit::imageview_create_info(_drawImage.imageFormat, _drawImage.image, VK_IMAGE_ASPECT_COLOR_BIT); + + VK_CHECK(vkCreateImageView(_device, &rview_info, nullptr, &_drawImage.imageView)); + + //add to deletion queues + _mainDeletionQueue.push_function([=]() { + vkDestroyImageView(_device, _drawImage.imageView, nullptr); + vmaDestroyImage(_allocator, _drawImage.image, _drawImage.allocation); + }); + +} + +void VkEngine::init_commands() +{ + VkCommandPoolCreateInfo commandPoolInfo = vkinit::command_pool_create_info(_graphicsQueueFamily, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + + for (int i = 0; i < static_cast(FRAME_OVERLAP); i++) { + + VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &_frames[i]._commandPool)); + + // allocate the default command buffer that we will use for rendering + VkCommandBufferAllocateInfo cmdAllocInfo = vkinit::command_buffer_allocate_info(_frames[i]._commandPool, 1); + + VK_CHECK(vkAllocateCommandBuffers(_device, &cmdAllocInfo, &_frames[i]._mainCommandBuffer)); + } +} + +void VkEngine::init_sync_structures() +{ + //create syncronization structures + //one fence to control when the gpu has finished rendering the frame, + //and 2 semaphores to syncronize rendering with swapchain + //we want the fence to start signalled so we can wait on it on the first frame + VkFenceCreateInfo fenceCreateInfo = vkinit::fence_create_info(VK_FENCE_CREATE_SIGNALED_BIT); + VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphore_create_info(); + + for (int i = 0; i < static_cast(FRAME_OVERLAP); i++) { + VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &_frames[i]._renderFence)); + + VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._swapchainSemaphore)); + VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._renderSemaphore)); + } +} diff --git a/VkEngine.h b/VkEngine.h new file mode 100644 index 0000000..36a175e --- /dev/null +++ b/VkEngine.h @@ -0,0 +1,110 @@ +#ifndef VKENGINE_H +#define VKENGINE_H + +#pragma once + +#include + +#include + +struct DeletionQueue +{ + std::deque> deletors; + + void push_function(std::function&& function) { + deletors.push_back(function); + } + + void flush() { + // reverse iterate the deletion queue to execute all the functions + for (auto it = deletors.rbegin(); it != deletors.rend(); it++) { + (*it)(); //call functors + } + + deletors.clear(); + } +}; + + +struct FrameData { + + VkCommandPool _commandPool; + VkCommandBuffer _mainCommandBuffer; + + VkSemaphore _swapchainSemaphore, _renderSemaphore; + VkFence _renderFence; + + DeletionQueue _deletionQueue; +}; + +constexpr unsigned int FRAME_OVERLAP = 2; + +class VkEngine +{ +public: + VkEngine(); + + bool _isInitialized{ false }; + int _frameNumber {0}; + bool stop_rendering{ false }; + VkExtent2D _windowExtent{ 1700 , 900 }; + + struct SDL_Window* _window{ nullptr }; + + VkInstance _instance;// Vulkan library handle + VkDebugUtilsMessengerEXT _debug_messenger;// Vulkan debug output handle + VkPhysicalDevice _chosenGPU;// GPU chosen as the default device + VkDevice _device; // Vulkan device for commands + VkSurfaceKHR _surface;// Vulkan window surface + + VkSwapchainKHR _swapchain; + VkFormat _swapchainImageFormat; + + std::vector _swapchainImages; + std::vector _swapchainImageViews; + VkExtent2D _swapchainExtent; + + FrameData _frames[FRAME_OVERLAP]; + + FrameData& get_current_frame() + { + return _frames[_frameNumber % FRAME_OVERLAP]; + } + + DeletionQueue _mainDeletionQueue; + + VkQueue _graphicsQueue; + uint32_t _graphicsQueueFamily; + + VmaAllocator _allocator; + + //draw resources + AllocatedImage _drawImage; + VkExtent2D _drawExtent; + + static VkEngine& Get(); + + //initializes everything in the engine + void init(); + + //shuts down the engine + void cleanup(); + + //draw loop + void draw(); + + //run main loop + void run(); + +private: + + void init_vulkan(); + void init_swapchain(); + void init_commands(); + void init_sync_structures(); + + void create_swapchain(uint32_t width, uint32_t height); + void destroy_swapchain(); +}; + +#endif // VKENGINE_H diff --git a/VkImages.cpp b/VkImages.cpp new file mode 100644 index 0000000..55e45e9 --- /dev/null +++ b/VkImages.cpp @@ -0,0 +1,34 @@ +#include "VkImages.h" +#include "VkInitializers.h" + +void vkutil::transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout) +{ + VkImageMemoryBarrier2 imageBarrier {.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + imageBarrier.pNext = nullptr; + + imageBarrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; + imageBarrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT; + + imageBarrier.oldLayout = currentLayout; + imageBarrier.newLayout = newLayout; + + VkImageAspectFlags aspectMask = (newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + imageBarrier.subresourceRange = vkinit::image_subresource_range(aspectMask); + imageBarrier.image = image; + + VkDependencyInfo depInfo {}; + depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + depInfo.pNext = nullptr; + + depInfo.imageMemoryBarrierCount = 1; + depInfo.pImageMemoryBarriers = &imageBarrier; + + vkCmdPipelineBarrier2(cmd, &depInfo); +} + +//VkImages::VkImages() +//{ + +//} diff --git a/VkImages.h b/VkImages.h new file mode 100644 index 0000000..7bc4b95 --- /dev/null +++ b/VkImages.h @@ -0,0 +1,22 @@ +#ifndef VKIMAGES_H +#define VKIMAGES_H + +#include + +#pragma once + +#include + +namespace vkutil { + +void transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout); +} + + +//class VkImages +//{ +//public: +// VkImages(); +//}; + +#endif // VKIMAGES_H diff --git a/VkInitializers.cpp b/VkInitializers.cpp new file mode 100644 index 0000000..7e93ccf --- /dev/null +++ b/VkInitializers.cpp @@ -0,0 +1,342 @@ +#include "VkInitializers.h" + +//> init_cmd +VkCommandPoolCreateInfo vkinit::command_pool_create_info(uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags /*= 0*/) +{ + VkCommandPoolCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + info.pNext = nullptr; + info.queueFamilyIndex = queueFamilyIndex; + info.flags = flags; + return info; +} + + +VkCommandBufferAllocateInfo vkinit::command_buffer_allocate_info( + VkCommandPool pool, uint32_t count /*= 1*/) +{ + VkCommandBufferAllocateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + info.pNext = nullptr; + + info.commandPool = pool; + info.commandBufferCount = count; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + return info; +} +//< init_cmd +// +//> init_cmd_draw +VkCommandBufferBeginInfo vkinit::command_buffer_begin_info(VkCommandBufferUsageFlags flags /*= 0*/) +{ + VkCommandBufferBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.pNext = nullptr; + + info.pInheritanceInfo = nullptr; + info.flags = flags; + return info; +} +//< init_cmd_draw + +//> init_sync +VkFenceCreateInfo vkinit::fence_create_info(VkFenceCreateFlags flags /*= 0*/) +{ + VkFenceCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + info.pNext = nullptr; + + info.flags = flags; + + return info; +} + +VkSemaphoreCreateInfo vkinit::semaphore_create_info(VkSemaphoreCreateFlags flags /*= 0*/) +{ + VkSemaphoreCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + info.pNext = nullptr; + info.flags = flags; + return info; +} +//< init_sync + +//> init_submit +VkSemaphoreSubmitInfo vkinit::semaphore_submit_info(VkPipelineStageFlags2 stageMask, VkSemaphore semaphore) +{ + VkSemaphoreSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.semaphore = semaphore; + submitInfo.stageMask = stageMask; + submitInfo.deviceIndex = 0; + submitInfo.value = 1; + + return submitInfo; +} + +VkCommandBufferSubmitInfo vkinit::command_buffer_submit_info(VkCommandBuffer cmd) +{ + VkCommandBufferSubmitInfo info{}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + info.pNext = nullptr; + info.commandBuffer = cmd; + info.deviceMask = 0; + + return info; +} + +VkSubmitInfo2 vkinit::submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSubmitInfo* signalSemaphoreInfo, + VkSemaphoreSubmitInfo* waitSemaphoreInfo) +{ + VkSubmitInfo2 info = {}; + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; + info.pNext = nullptr; + + info.waitSemaphoreInfoCount = waitSemaphoreInfo == nullptr ? 0 : 1; + info.pWaitSemaphoreInfos = waitSemaphoreInfo; + + info.signalSemaphoreInfoCount = signalSemaphoreInfo == nullptr ? 0 : 1; + info.pSignalSemaphoreInfos = signalSemaphoreInfo; + + info.commandBufferInfoCount = 1; + info.pCommandBufferInfos = cmd; + + return info; +} +//< init_submit + +VkPresentInfoKHR vkinit::present_info() +{ + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.pNext = 0; + + info.swapchainCount = 0; + info.pSwapchains = nullptr; + info.pWaitSemaphores = nullptr; + info.waitSemaphoreCount = 0; + info.pImageIndices = nullptr; + + return info; +} + +//> color_info +VkRenderingAttachmentInfo vkinit::attachment_info( + VkImageView view, VkClearValue* clear ,VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/) +{ + VkRenderingAttachmentInfo colorAttachment {}; + colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + colorAttachment.pNext = nullptr; + + colorAttachment.imageView = view; + colorAttachment.imageLayout = layout; + colorAttachment.loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + if (clear) { + colorAttachment.clearValue = *clear; + } + + return colorAttachment; +} +//< color_info +//> depth_info +VkRenderingAttachmentInfo vkinit::depth_attachment_info( + VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/) +{ + VkRenderingAttachmentInfo depthAttachment {}; + depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + depthAttachment.pNext = nullptr; + + depthAttachment.imageView = view; + depthAttachment.imageLayout = layout; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + depthAttachment.clearValue.depthStencil.depth = 0.f; + + return depthAttachment; +} +//< depth_info +//> render_info +VkRenderingInfo vkinit::rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, + VkRenderingAttachmentInfo* depthAttachment) +{ + VkRenderingInfo renderInfo {}; + renderInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + renderInfo.pNext = nullptr; + + renderInfo.renderArea = VkRect2D { VkOffset2D { 0, 0 }, renderExtent }; + renderInfo.layerCount = 1; + renderInfo.colorAttachmentCount = 1; + renderInfo.pColorAttachments = colorAttachment; + renderInfo.pDepthAttachment = depthAttachment; + renderInfo.pStencilAttachment = nullptr; + + return renderInfo; +} +//< render_info +//> subresource +VkImageSubresourceRange vkinit::image_subresource_range(VkImageAspectFlags aspectMask) +{ + VkImageSubresourceRange subImage {}; + subImage.aspectMask = aspectMask; + subImage.baseMipLevel = 0; + subImage.levelCount = VK_REMAINING_MIP_LEVELS; + subImage.baseArrayLayer = 0; + subImage.layerCount = VK_REMAINING_ARRAY_LAYERS; + + return subImage; +} +//< subresource + + + +VkDescriptorSetLayoutBinding vkinit::descriptorset_layout_binding(VkDescriptorType type, VkShaderStageFlags stageFlags, + uint32_t binding) +{ + VkDescriptorSetLayoutBinding setbind = {}; + setbind.binding = binding; + setbind.descriptorCount = 1; + setbind.descriptorType = type; + setbind.pImmutableSamplers = nullptr; + setbind.stageFlags = stageFlags; + + return setbind; +} + +VkDescriptorSetLayoutCreateInfo vkinit::descriptorset_layout_create_info(VkDescriptorSetLayoutBinding* bindings, + uint32_t bindingCount) +{ + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.pNext = nullptr; + + info.pBindings = bindings; + info.bindingCount = bindingCount; + info.flags = 0; + + return info; +} + +VkWriteDescriptorSet vkinit::write_descriptor_image(VkDescriptorType type, VkDescriptorSet dstSet, + VkDescriptorImageInfo* imageInfo, uint32_t binding) +{ + VkWriteDescriptorSet write = {}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.pNext = nullptr; + + write.dstBinding = binding; + write.dstSet = dstSet; + write.descriptorCount = 1; + write.descriptorType = type; + write.pImageInfo = imageInfo; + + return write; +} + +VkWriteDescriptorSet vkinit::write_descriptor_buffer(VkDescriptorType type, VkDescriptorSet dstSet, + VkDescriptorBufferInfo* bufferInfo, uint32_t binding) +{ + VkWriteDescriptorSet write = {}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.pNext = nullptr; + + write.dstBinding = binding; + write.dstSet = dstSet; + write.descriptorCount = 1; + write.descriptorType = type; + write.pBufferInfo = bufferInfo; + + return write; +} + +VkDescriptorBufferInfo vkinit::buffer_info(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) +{ + VkDescriptorBufferInfo binfo {}; + binfo.buffer = buffer; + binfo.offset = offset; + binfo.range = range; + return binfo; +} + +//> image_set +VkImageCreateInfo vkinit::image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent) +{ + VkImageCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.pNext = nullptr; + + info.imageType = VK_IMAGE_TYPE_2D; + + info.format = format; + info.extent = extent; + + info.mipLevels = 1; + info.arrayLayers = 1; + + //for MSAA. we will not be using it by default, so default it to 1 sample per pixel. + info.samples = VK_SAMPLE_COUNT_1_BIT; + + //optimal tiling, which means the image is stored on the best gpu format + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = usageFlags; + + return info; +} + +VkImageViewCreateInfo vkinit::imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags) +{ + // build a image-view for the depth image to use for rendering + VkImageViewCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.pNext = nullptr; + + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.image = image; + info.format = format; + info.subresourceRange.baseMipLevel = 0; + info.subresourceRange.levelCount = 1; + info.subresourceRange.baseArrayLayer = 0; + info.subresourceRange.layerCount = 1; + info.subresourceRange.aspectMask = aspectFlags; + + return info; +} +//< image_set +VkPipelineLayoutCreateInfo vkinit::pipeline_layout_create_info() +{ + VkPipelineLayoutCreateInfo info {}; + info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + info.pNext = nullptr; + + // empty defaults + info.flags = 0; + info.setLayoutCount = 0; + info.pSetLayouts = nullptr; + info.pushConstantRangeCount = 0; + info.pPushConstantRanges = nullptr; + return info; +} + +VkPipelineShaderStageCreateInfo vkinit::pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, + VkShaderModule shaderModule, + const char * entry) +{ + VkPipelineShaderStageCreateInfo info {}; + info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + info.pNext = nullptr; + + // shader stage + info.stage = stage; + // module containing the code for this shader stage + info.module = shaderModule; + // the entry point of the shader + info.pName = entry; + return info; +} + +//VkInitializers::VkInitializers() +//{ + +//} diff --git a/VkInitializers.h b/VkInitializers.h new file mode 100644 index 0000000..c08fc92 --- /dev/null +++ b/VkInitializers.h @@ -0,0 +1,62 @@ +#ifndef VKINITIALIZERS_H +#define VKINITIALIZERS_H + +#include + +#pragma once + +#include + +namespace vkinit { +//> init_cmd +VkCommandPoolCreateInfo command_pool_create_info(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags flags = 0); +VkCommandBufferAllocateInfo command_buffer_allocate_info(VkCommandPool pool, uint32_t count = 1); +//< init_cmd + +VkCommandBufferBeginInfo command_buffer_begin_info(VkCommandBufferUsageFlags flags = 0); +VkCommandBufferSubmitInfo command_buffer_submit_info(VkCommandBuffer cmd); + +VkFenceCreateInfo fence_create_info(VkFenceCreateFlags flags = 0); + +VkSemaphoreCreateInfo semaphore_create_info(VkSemaphoreCreateFlags flags = 0); + +VkSubmitInfo2 submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSubmitInfo* signalSemaphoreInfo, + VkSemaphoreSubmitInfo* waitSemaphoreInfo); +VkPresentInfoKHR present_info(); + +VkRenderingAttachmentInfo attachment_info(VkImageView view, VkClearValue* clear, VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/); + +VkRenderingAttachmentInfo depth_attachment_info(VkImageView view, + VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/); + +VkRenderingInfo rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, + VkRenderingAttachmentInfo* depthAttachment); + +VkImageSubresourceRange image_subresource_range(VkImageAspectFlags aspectMask); + +VkSemaphoreSubmitInfo semaphore_submit_info(VkPipelineStageFlags2 stageMask, VkSemaphore semaphore); +VkDescriptorSetLayoutBinding descriptorset_layout_binding(VkDescriptorType type, VkShaderStageFlags stageFlags, + uint32_t binding); +VkDescriptorSetLayoutCreateInfo descriptorset_layout_create_info(VkDescriptorSetLayoutBinding* bindings, + uint32_t bindingCount); +VkWriteDescriptorSet write_descriptor_image(VkDescriptorType type, VkDescriptorSet dstSet, + VkDescriptorImageInfo* imageInfo, uint32_t binding); +VkWriteDescriptorSet write_descriptor_buffer(VkDescriptorType type, VkDescriptorSet dstSet, + VkDescriptorBufferInfo* bufferInfo, uint32_t binding); +VkDescriptorBufferInfo buffer_info(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range); + +VkImageCreateInfo image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent); +VkImageViewCreateInfo imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags); +VkPipelineLayoutCreateInfo pipeline_layout_create_info(); +VkPipelineShaderStageCreateInfo pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, + VkShaderModule shaderModule, + const char * entry = "main"); +} // namespace vkinit + +//class VkInitializers +//{ +//public: +// VkInitializers(); +//}; + +#endif // VKINITIALIZERS_H diff --git a/VkLoader.cpp b/VkLoader.cpp new file mode 100644 index 0000000..361b914 --- /dev/null +++ b/VkLoader.cpp @@ -0,0 +1,6 @@ +#include "VkLoader.h" + +VkLoader::VkLoader() +{ + +} diff --git a/VkLoader.h b/VkLoader.h new file mode 100644 index 0000000..52ba743 --- /dev/null +++ b/VkLoader.h @@ -0,0 +1,12 @@ +#ifndef VKLOADER_H +#define VKLOADER_H + +#include + +class VkLoader +{ +public: + VkLoader(); +}; + +#endif // VKLOADER_H diff --git a/VkMain.cpp b/VkMain.cpp new file mode 100644 index 0000000..4f32567 --- /dev/null +++ b/VkMain.cpp @@ -0,0 +1,17 @@ +#include "VkMain.h" + +VkMain::VkMain() +{ + +} + +void VkMain::mainRun() +{ + VkEngine engine; + + engine.init(); + + engine.run(); + + engine.cleanup(); +} diff --git a/VkMain.h b/VkMain.h new file mode 100644 index 0000000..e8ccbab --- /dev/null +++ b/VkMain.h @@ -0,0 +1,15 @@ +#ifndef VKMAIN_H +#define VKMAIN_H + +#include + +#include + +class VkMain +{ +public: + VkMain(); + void mainRun(); +}; + +#endif // VKMAIN_H diff --git a/VkPipelines.cpp b/VkPipelines.cpp new file mode 100644 index 0000000..078cf2e --- /dev/null +++ b/VkPipelines.cpp @@ -0,0 +1,6 @@ +#include "VkPipelines.h" + +VkPipelines::VkPipelines() +{ + +} diff --git a/VkPipelines.h b/VkPipelines.h new file mode 100644 index 0000000..79c18e2 --- /dev/null +++ b/VkPipelines.h @@ -0,0 +1,12 @@ +#ifndef VKPIPELINES_H +#define VKPIPELINES_H + +#include + +class VkPipelines +{ +public: + VkPipelines(); +}; + +#endif // VKPIPELINES_H diff --git a/VkTest.pro b/VkTest.pro index 51d65e1..d834cd2 100644 --- a/VkTest.pro +++ b/VkTest.pro @@ -2,25 +2,41 @@ QT += CONFIG += c++17 -INCLUDEPATH += /usr/include/GLFW +INCLUDEPATH += /usr/include/vulkan \ + $$PWD/third_party \ + $$PWD/third_party/vkbootstrap \ + $$PWD/third_party/vkbootstrap/build \ + $$PWD/third_party/fmt/include \ + $$PWD/third_party/SDL/build/include/SDL2 \ + $$PWD/third_party/SDL/build/include-config-/SDL2 \ + $$PWD/third_party/fmt/build -LIBS += -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi +LIBS += -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi -lSDL2main -lSDL2 -lvk-bootstrap \ + -L$$PWD/third_party/fmt/build -lfmt SOURCES += \ HelloTriangleApplication.cpp \ + VkDescriptors.cpp \ + VkEngine.cpp \ + VkImages.cpp \ + VkInitializers.cpp \ + VkLoader.cpp \ + VkMain.cpp \ + VkPipelines.cpp \ main.cpp HEADERS += \ - HelloTriangleApplication.h + HelloTriangleApplication.h \ + VkDescriptors.h \ + VkEngine.h \ + VkImages.h \ + VkInitializers.h \ + VkLoader.h \ + VkMain.h \ + VkPipelines.h \ + VkTypes.h DISTFILES += \ - android/AndroidManifest.xml \ - android/build.gradle \ - android/gradle/wrapper/gradle-wrapper.jar \ - android/gradle/wrapper/gradle-wrapper.properties \ - android/gradlew \ - android/gradlew.bat \ - android/res/values/libs.xml \ shaders/compile.sh \ shaders/frag.spv \ shaders/shader.frag \ @@ -28,7 +44,15 @@ DISTFILES += \ shaders/vert.spv contains(ANDROID_TARGET_ARCH,arm64-v8a) { + QT += ANDROID_PACKAGE_SOURCE_DIR = \ $$PWD/android - OTHER_FILES += android/src/Vulkan + OTHER_FILES += android/src/Vulkan \ + android/AndroidManifest.xml \ + android/build.gradle \ + android/gradle/wrapper/gradle-wrapper.jar \ + android/gradle/wrapper/gradle-wrapper.properties \ + android/gradlew \ + android/gradlew.bat \ + android/res/values/libs.xml } diff --git a/VkTest.pro.user b/VkTest.pro.user index 8950846..5f7e840 100644 --- a/VkTest.pro.user +++ b/VkTest.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -56,7 +56,8 @@ ProjectExplorer.Project.PluginSettings - true + false + {afe80e93-8983-4e43-ba75-d87634bcd04b} @@ -314,7 +315,7 @@ false false true - /home/ali-mehrabani/Qt_projects/VkTest + /home/ali-mehrabani/Qt_projects/build-VkTest-Desktop_Qt_5_13_2_GCC_64bit-Debug 1 diff --git a/VkTypes.h b/VkTypes.h new file mode 100644 index 0000000..960a301 --- /dev/null +++ b/VkTypes.h @@ -0,0 +1,41 @@ +#ifndef VKTYPES_H +#define VKTYPES_H + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +struct AllocatedImage { + VkImage image; + VkImageView imageView; + VmaAllocation allocation; + VkExtent3D imageExtent; + VkFormat imageFormat; +}; + +#define VK_CHECK(x) \ + do { \ + VkResult err = x; \ + if (err) { \ + fmt::print("Detected Vulkan error: {}", string_VkResult(err)); \ + abort(); \ + } \ + } while (0) + +#endif // VKTYPES_H diff --git a/android-libVkTest.so-deployment-settings.json b/android-libVkTest.so-deployment-settings.json new file mode 100644 index 0000000..2423cfd --- /dev/null +++ b/android-libVkTest.so-deployment-settings.json @@ -0,0 +1,17 @@ +{ + "description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.", + "qt": "/opt/Qt5.13.2/5.13.2/android_arm64_v8a", + "sdk": "/home/ali-mehrabani/host-projects/Android/Sdk", + "sdkBuildToolsRevision": "30.0.0", + "ndk": "/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b", + "toolchain-prefix": "llvm", + "tool-prefix": "llvm", + "toolchain-version": "4.9", + "ndk-host": "linux-x86_64", + "target-architecture": "arm64-v8a", + "android-package-source-directory": "/home/ali-mehrabani/Qt_projects/VkTest/android", + "qml-root-path": "/home/ali-mehrabani/Qt_projects/VkTest", + "stdcpp-path": "/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so", + "useLLVM": true, + "application-binary": "/home/ali-mehrabani/Qt_projects/VkTest/libVkTest.so" +} diff --git a/main.cpp b/main.cpp index 8b95b15..73cfbd0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ -#include +//#include +#include #include #include @@ -6,10 +7,12 @@ int main(int /*argc*/, char */*argv*/[]) { - HelloTriangleApplication app; +// HelloTriangleApplication app; + VkMain vkMain; try { - app.run(); +// app.run(); + vkMain.mainRun(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE;