Browse Source

Push files to the new remote

master
AliMehrabani 4 weeks ago
parent
commit
dcf2a5ab10
  1. 2
      .gitignore
  2. 29
      .qmake.stash
  3. 266
      HelloTriangleApplication.cpp
  4. 37
      HelloTriangleApplication.h
  5. 6
      VkDescriptors.cpp
  6. 12
      VkDescriptors.h
  7. 402
      VkEngine.cpp
  8. 110
      VkEngine.h
  9. 34
      VkImages.cpp
  10. 22
      VkImages.h
  11. 342
      VkInitializers.cpp
  12. 62
      VkInitializers.h
  13. 6
      VkLoader.cpp
  14. 12
      VkLoader.h
  15. 17
      VkMain.cpp
  16. 15
      VkMain.h
  17. 6
      VkPipelines.cpp
  18. 12
      VkPipelines.h
  19. 46
      VkTest.pro
  20. 7
      VkTest.pro.user
  21. 41
      VkTypes.h
  22. 17
      android-libVkTest.so-deployment-settings.json
  23. 9
      main.cpp

2
.gitignore

@ -1,2 +1,4 @@
.gradle/ .gradle/
build/ build/
third_party/
glm/

29
.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

266
HelloTriangleApplication.cpp

@ -52,18 +52,18 @@ void HelloTriangleApplication::run()
void HelloTriangleApplication::initWindow() 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); // _window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
glfwSetWindowUserPointer(_window, this); // glfwSetWindowUserPointer(_window, this);
glfwSetFramebufferSizeCallback(_window, framebufferResizeCallback); // glfwSetFramebufferSizeCallback(_window, framebufferResizeCallback);
} }
void HelloTriangleApplication::framebufferResizeCallback(GLFWwindow* window, int /*width*/, int /*height*/) { void HelloTriangleApplication::framebufferResizeCallback(QQuickWindow* window, int /*width*/, int /*height*/) {
auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window)); // auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
app->framebufferResized = true; // app->framebufferResized = true;
} }
@ -95,6 +95,32 @@ void HelloTriangleApplication::initVulkan()
createSyncObjects(); createSyncObjects();
} }
bool HelloTriangleApplication::checkValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char* layerName : validationLayers) {
bool layerFound = false;
for (const auto& layerProperties : availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if (!layerFound) {
return false;
}
}
return true;
}
void HelloTriangleApplication::createInstance() void HelloTriangleApplication::createInstance()
{ {
VkApplicationInfo appInfo{}; 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<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char* layerName : validationLayers) {
bool layerFound = false;
for (const auto& layerProperties : availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if (!layerFound) {
return false;
}
}
return true;
}
std::vector<const char*> HelloTriangleApplication::getRequiredExtensions() std::vector<const char*> HelloTriangleApplication::getRequiredExtensions()
{ {
uint32_t glfwExtensionCount = 0; uint32_t glfwExtensionCount = 0;
const char** glfwExtensions; const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); // glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
@ -188,6 +174,20 @@ std::vector<const char*> HelloTriangleApplication::getRequiredExtensions()
return extensions; 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) { void HelloTriangleApplication::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
createInfo = {}; createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
@ -203,9 +203,9 @@ void HelloTriangleApplication::populateDebugMessengerCreateInfo(VkDebugUtilsMess
void HelloTriangleApplication::createSurface() void HelloTriangleApplication::createSurface()
{ {
if (glfwCreateWindowSurface(_instance, _window, nullptr, &_surface) != VK_SUCCESS) { // if (glfwCreateWindowSurface(_instance, _window, nullptr, &_surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!"); // throw std::runtime_error("failed to create window surface!");
} // }
} }
void HelloTriangleApplication::pickPhysicalDevice() { void HelloTriangleApplication::pickPhysicalDevice() {
@ -254,49 +254,44 @@ bool HelloTriangleApplication::isDeviceSuitable(VkPhysicalDevice device) {
return indices.isComplete() && extensionsSupported && swapChainAdequate; return indices.isComplete() && extensionsSupported && swapChainAdequate;
} }
void HelloTriangleApplication::createLogicalDevice() bool HelloTriangleApplication::checkDeviceExtensionSupport(VkPhysicalDevice device) {
{ uint32_t extensionCount;
QueueFamilyIndices indices = findQueueFamilies(_physicalDevice); vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos; std::vector<VkExtensionProperties> availableExtensions(extensionCount);
std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()}; vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
float queuePriority = 1.0f; std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
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{}; for (const auto& extension : availableExtensions) {
requiredExtensions.erase(extension.extensionName);
}
VkDeviceCreateInfo createInfo{}; return requiredExtensions.empty();
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; }
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); SwapChainSupportDetails HelloTriangleApplication::querySwapChainSupport(VkPhysicalDevice device) {
createInfo.pQueueCreateInfos = queueCreateInfos.data(); SwapChainSupportDetails details;
createInfo.pEnabledFeatures = &deviceFeatures; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, _surface, &details.capabilities);
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); uint32_t formatCount;
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &formatCount, nullptr);
if (enableValidationLayers) { if (formatCount != 0) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); details.formats.resize(formatCount);
createInfo.ppEnabledLayerNames = validationLayers.data(); vkGetPhysicalDeviceSurfaceFormatsKHR(device, _surface, &formatCount, details.formats.data());
} else {
createInfo.enabledLayerCount = 0;
} }
if (vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device) != VK_SUCCESS) { uint32_t presentModeCount;
throw std::runtime_error("failed to create logical device!"); 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); return details;
vkGetDeviceQueue(_device, indices.presentFamily.value(), 0, &_presentQueue);
} }
QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice device) {
@ -331,6 +326,51 @@ QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice
return indices; return indices;
} }
void HelloTriangleApplication::createLogicalDevice()
{
QueueFamilyIndices indices = findQueueFamilies(_physicalDevice);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> 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<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
if (enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
createInfo.enabledLayerCount = 0;
}
if (vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
vkGetDeviceQueue(_device, indices.graphicsFamily.value(), 0, &_graphicsQueue);
vkGetDeviceQueue(_device, indices.presentFamily.value(), 0, &_presentQueue);
}
void HelloTriangleApplication::createSwapChain() { void HelloTriangleApplication::createSwapChain() {
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(_physicalDevice); SwapChainSupportDetails swapChainSupport = querySwapChainSupport(_physicalDevice);
@ -385,22 +425,6 @@ void HelloTriangleApplication::createSwapChain() {
_swapChainExtent = extent; _swapChainExtent = extent;
} }
bool HelloTriangleApplication::checkDeviceExtensionSupport(VkPhysicalDevice device) {
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
for (const auto& extension : availableExtensions) {
requiredExtensions.erase(extension.extensionName);
}
return requiredExtensions.empty();
}
VkSurfaceFormatKHR HelloTriangleApplication::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) { VkSurfaceFormatKHR HelloTriangleApplication::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
for (const auto& availableFormat : availableFormats) { for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { 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; return capabilities.currentExtent;
} else { } else {
int width, height; int width, height;
glfwGetFramebufferSize(_window, &width, &height); // glfwGetFramebufferSize(_window, &width, &height);
VkExtent2D actualExtent = { VkExtent2D actualExtent = {
static_cast<uint32_t>(width), static_cast<uint32_t>(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() { void HelloTriangleApplication::createImageViews() {
_swapChainImageViews.resize(_swapChainImages.size()); _swapChainImageViews.resize(_swapChainImages.size());
for (size_t i = 0; i < _swapChainImages.size(); i++) { for (size_t i = 0; i < _swapChainImages.size(); i++) {
@ -1017,10 +1017,10 @@ void HelloTriangleApplication::createSyncObjects() {
void HelloTriangleApplication::mainLoop() void HelloTriangleApplication::mainLoop()
{ {
while (!glfwWindowShouldClose(_window)) { // while (!glfwWindowShouldClose(_window)) {
glfwPollEvents(); // glfwPollEvents();
drawFrame(); // drawFrame();
} // }
vkDeviceWaitIdle(_device); vkDeviceWaitIdle(_device);
} }
@ -1107,10 +1107,10 @@ void HelloTriangleApplication::updateUniformBuffer(uint32_t currentImage) {
void HelloTriangleApplication::recreateSwapChain() { void HelloTriangleApplication::recreateSwapChain() {
int width = 0, height = 0; int width = 0, height = 0;
glfwGetFramebufferSize(_window, &width, &height); // glfwGetFramebufferSize(_window, &width, &height);
while (width == 0 || height == 0) { while (width == 0 || height == 0) {
glfwGetFramebufferSize(_window, &width, &height); // glfwGetFramebufferSize(_window, &width, &height);
glfwWaitEvents(); // glfwWaitEvents();
} }
vkDeviceWaitIdle(_device); vkDeviceWaitIdle(_device);
@ -1177,7 +1177,7 @@ void HelloTriangleApplication::cleanup()
vkDestroyInstance(_instance, nullptr); vkDestroyInstance(_instance, nullptr);
glfwDestroyWindow(_window); // glfwDestroyWindow(_window);
glfwTerminate(); // glfwTerminate();
} }

37
HelloTriangleApplication.h

@ -7,21 +7,23 @@
const bool enableValidationLayers = true; const bool enableValidationLayers = true;
#endif #endif
//#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#define VK_USE_PLATFORM_ //#define VK_USE_PLATFORM_
#define GLFW_INCLUDE_VULKAN //#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> //#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_ //#define GLFW_EXPOSE_NATIVE_
#include <GLFW/glfw3native.h> //#include <GLFW/glfw3native.h>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <chrono> #include <chrono>
#include <QObject> #include <QObject>
#include <QtQuick/QQuickWindow>
#include <iostream> #include <iostream>
#include <optional> #include <optional>
#include <cstdint> // Necessary for uint32_t #include <cstdint> // Necessary for uint32_t
@ -30,6 +32,12 @@
#include <fstream> #include <fstream>
#include <array> #include <array>
#ifdef Q_OS_ANDROID
const QString TARGET_PLATFORM = "Android";
#else
const QString TARGET_PLATFORM = "Linux";
#endif
const int MAX_FRAMES_IN_FLIGHT = 2; const int MAX_FRAMES_IN_FLIGHT = 2;
struct QueueFamilyIndices { struct QueueFamilyIndices {
@ -48,8 +56,8 @@ struct SwapChainSupportDetails {
}; };
struct Vertex { struct Vertex {
glm::vec2 pos; alignas(16) glm::vec2 pos;
glm::vec3 color; alignas(16) glm::vec3 color;
static VkVertexInputBindingDescription getBindingDescription() { static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription{}; VkVertexInputBindingDescription bindingDescription{};
@ -78,9 +86,9 @@ struct Vertex {
}; };
struct UniformBufferObject { struct UniformBufferObject {
glm::mat4 model; alignas(16) glm::mat4 model;
glm::mat4 view; alignas(16) glm::mat4 view;
glm::mat4 proj; alignas(16) glm::mat4 proj;
}; };
class HelloTriangleApplication class HelloTriangleApplication
@ -98,7 +106,9 @@ public:
return VK_FALSE; return VK_FALSE;
} }
static std::vector<char> readFile(const std::string& filename); static std::vector<char> 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: private:
void initWindow(); void initWindow();
@ -180,7 +190,8 @@ private:
uint32_t currentFrame = 0; uint32_t currentFrame = 0;
bool framebufferResized = false; bool framebufferResized = false;
GLFWwindow *_window; // GLFWwindow *_window;
QQuickWindow* _window;
VkInstance _instance; VkInstance _instance;
VkDebugUtilsMessengerEXT _debugMessenger; VkDebugUtilsMessengerEXT _debugMessenger;
VkPhysicalDevice _physicalDevice; VkPhysicalDevice _physicalDevice;

6
VkDescriptors.cpp

@ -0,0 +1,6 @@
#include "VkDescriptors.h"
VkDescriptors::VkDescriptors()
{
}

12
VkDescriptors.h

@ -0,0 +1,12 @@
#ifndef VKDESCRIPTORS_H
#define VKDESCRIPTORS_H
#include <QObject>
class VkDescriptors
{
public:
VkDescriptors();
};
#endif // VKDESCRIPTORS_H

402
VkEngine.cpp

@ -0,0 +1,402 @@
#include "VkEngine.h"
#include <SDL.h>
#include <SDL_vulkan.h>
#include <VkInitializers.h>
#include <VkTypes.h>
//bootstrap library
#include "VkBootstrap.h"
#include "VkImages.h"
#define VMA_IMPLEMENTATION
#include "vma/vk_mem_alloc.h"
#include <chrono>
#include <thread>
//< 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_WindowFlags>(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<int>(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<int>(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<int>(_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<int>(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<int>(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));
}
}

110
VkEngine.h

@ -0,0 +1,110 @@
#ifndef VKENGINE_H
#define VKENGINE_H
#pragma once
#include <VkTypes.h>
#include <QObject>
struct DeletionQueue
{
std::deque<std::function<void()>> deletors;
void push_function(std::function<void()>&& 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<VkImage> _swapchainImages;
std::vector<VkImageView> _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

34
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()
//{
//}

22
VkImages.h

@ -0,0 +1,22 @@
#ifndef VKIMAGES_H
#define VKIMAGES_H
#include <QObject>
#pragma once
#include <vulkan/vulkan.h>
namespace vkutil {
void transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout);
}
//class VkImages
//{
//public:
// VkImages();
//};
#endif // VKIMAGES_H

342
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()
//{
//}

62
VkInitializers.h

@ -0,0 +1,62 @@
#ifndef VKINITIALIZERS_H
#define VKINITIALIZERS_H
#include <QObject>
#pragma once
#include <VkTypes.h>
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

6
VkLoader.cpp

@ -0,0 +1,6 @@
#include "VkLoader.h"
VkLoader::VkLoader()
{
}

12
VkLoader.h

@ -0,0 +1,12 @@
#ifndef VKLOADER_H
#define VKLOADER_H
#include <QObject>
class VkLoader
{
public:
VkLoader();
};
#endif // VKLOADER_H

17
VkMain.cpp

@ -0,0 +1,17 @@
#include "VkMain.h"
VkMain::VkMain()
{
}
void VkMain::mainRun()
{
VkEngine engine;
engine.init();
engine.run();
engine.cleanup();
}

15
VkMain.h

@ -0,0 +1,15 @@
#ifndef VKMAIN_H
#define VKMAIN_H
#include <VkEngine.h>
#include <QObject>
class VkMain
{
public:
VkMain();
void mainRun();
};
#endif // VKMAIN_H

6
VkPipelines.cpp

@ -0,0 +1,6 @@
#include "VkPipelines.h"
VkPipelines::VkPipelines()
{
}

12
VkPipelines.h

@ -0,0 +1,12 @@
#ifndef VKPIPELINES_H
#define VKPIPELINES_H
#include <QObject>
class VkPipelines
{
public:
VkPipelines();
};
#endif // VKPIPELINES_H

46
VkTest.pro

@ -2,25 +2,41 @@ QT +=
CONFIG += c++17 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 += \ SOURCES += \
HelloTriangleApplication.cpp \ HelloTriangleApplication.cpp \
VkDescriptors.cpp \
VkEngine.cpp \
VkImages.cpp \
VkInitializers.cpp \
VkLoader.cpp \
VkMain.cpp \
VkPipelines.cpp \
main.cpp main.cpp
HEADERS += \ HEADERS += \
HelloTriangleApplication.h HelloTriangleApplication.h \
VkDescriptors.h \
VkEngine.h \
VkImages.h \
VkInitializers.h \
VkLoader.h \
VkMain.h \
VkPipelines.h \
VkTypes.h
DISTFILES += \ 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/compile.sh \
shaders/frag.spv \ shaders/frag.spv \
shaders/shader.frag \ shaders/shader.frag \
@ -28,7 +44,15 @@ DISTFILES += \
shaders/vert.spv shaders/vert.spv
contains(ANDROID_TARGET_ARCH,arm64-v8a) { contains(ANDROID_TARGET_ARCH,arm64-v8a) {
QT +=
ANDROID_PACKAGE_SOURCE_DIR = \ ANDROID_PACKAGE_SOURCE_DIR = \
$$PWD/android $$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
} }

7
VkTest.pro.user

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.10.1, 2024-10-20T10:12:03. --> <!-- Written by QtCreator 4.10.1, 2024-10-29T21:23:38. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
@ -56,7 +56,8 @@
<variable>ProjectExplorer.Project.PluginSettings</variable> <variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/> <valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value> <value type="bool" key="ClangCodeModel.UseGlobalConfig">false</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">{afe80e93-8983-4e43-ba75-d87634bcd04b}</value>
</valuemap> </valuemap>
</data> </data>
<data> <data>
@ -314,7 +315,7 @@
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value> <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory">/home/ali-mehrabani/Qt_projects/VkTest</value> <value type="QString" key="RunConfiguration.WorkingDirectory"></value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/ali-mehrabani/Qt_projects/build-VkTest-Desktop_Qt_5_13_2_GCC_64bit-Debug</value> <value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/ali-mehrabani/Qt_projects/build-VkTest-Desktop_Qt_5_13_2_GCC_64bit-Debug</value>
</valuemap> </valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value> <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>

41
VkTypes.h

@ -0,0 +1,41 @@
#ifndef VKTYPES_H
#define VKTYPES_H
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <span>
#include <array>
#include <functional>
#include <deque>
#include <vulkan.h>
#include <vk_enum_string_helper.h>
#include <vma/vk_mem_alloc.h>
#include <fmt/core.h>
#include <glm/mat4x4.hpp>
#include <glm/vec4.hpp>
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

17
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"
}

9
main.cpp

@ -1,4 +1,5 @@
#include <HelloTriangleApplication.h> //#include <HelloTriangleApplication.h>
#include <VkMain.h>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
@ -6,10 +7,12 @@
int main(int /*argc*/, char */*argv*/[]) { int main(int /*argc*/, char */*argv*/[]) {
HelloTriangleApplication app; // HelloTriangleApplication app;
VkMain vkMain;
try { try {
app.run(); // app.run();
vkMain.mainRun();
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;

Loading…
Cancel
Save