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;