diff --git a/Vulkan/Vulkan.vcxproj b/Vulkan/Vulkan.vcxproj
index 1b57a78..ca5e350 100644
--- a/Vulkan/Vulkan.vcxproj
+++ b/Vulkan/Vulkan.vcxproj
@@ -150,10 +150,15 @@
+
+
+
+
+
diff --git a/Vulkan/Vulkan.vcxproj.filters b/Vulkan/Vulkan.vcxproj.filters
index 7bdbeb6..9f4a713 100644
--- a/Vulkan/Vulkan.vcxproj.filters
+++ b/Vulkan/Vulkan.vcxproj.filters
@@ -32,6 +32,21 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/Vulkan/res/shaders/shader.vert b/Vulkan/res/shaders/shader.vert
index 66d6766..e368b85 100644
--- a/Vulkan/res/shaders/shader.vert
+++ b/Vulkan/res/shaders/shader.vert
@@ -1,20 +1,18 @@
#version 450
+layout(binding = 0) uniform UniformBufferObject
+{
+ mat4 model;
+ mat4 view;
+ mat4 projection;
+} ubo;
+
+layout(location = 0) in vec2 inPosition;
+layout(location = 1) in vec3 inColor;
+
layout(location = 0) out vec3 fragColor;
-vec2 positions[3] = vec2[](
- vec2(0.0, -0.5),
- vec2(0.5, 0.5),
- vec2(-0.5, 0.5)
-);
-
-vec3 colors[3] = vec3[](
- vec3(1.0, 0.0, 0.0),
- vec3(0.0, 1.0, 0.0),
- vec3(0.0, 0.0, 1.0)
-);
-
void main() {
- gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
- fragColor = colors[gl_VertexIndex];
+ gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
+ fragColor = inColor;
}
\ No newline at end of file
diff --git a/Vulkan/res/shaders/vert.spv b/Vulkan/res/shaders/vert.spv
index a41dd2c..4092755 100644
Binary files a/Vulkan/res/shaders/vert.spv and b/Vulkan/res/shaders/vert.spv differ
diff --git a/Vulkan/src/Buffer.h b/Vulkan/src/Buffer.h
new file mode 100644
index 0000000..4fffca2
--- /dev/null
+++ b/Vulkan/src/Buffer.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "Common.h"
+#include "Instance.h"
+#include
+#include
+
+class Buffer
+{
+private:
+ Instance& instance;
+
+ VkDeviceMemory memory;
+ VkBuffer handle;
+ VkDeviceSize size;
+ int count;
+
+ void* mappedData = nullptr;
+
+public:
+ Buffer(Instance& instance, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDeviceSize size, int count)
+ : instance{instance}, size{size}, count{count}
+ {
+ VkBufferCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ createInfo.size = size * (VkDeviceSize)count;
+ createInfo.usage = usage;
+ createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer");
+
+ VkMemoryRequirements memoryRequirements;
+ vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements);
+
+ VkMemoryAllocateInfo allocateInfo{};
+ allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocateInfo.allocationSize = memoryRequirements.size;
+ allocateInfo.memoryTypeIndex = FindMemoryType(instance, memoryRequirements.memoryTypeBits, properties);
+
+ VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Failed to allocate buffer memory");
+
+ vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
+ }
+
+ ~Buffer()
+ {
+ vkFreeMemory(instance.GetDevice(), memory, nullptr);
+ vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
+ }
+
+ void Update(void* indexData, int index)
+ {
+ ASSERT(index >= 0 && index < count, "instance is outside of the buffer");
+
+ if (mappedData == nullptr)
+ {
+ void* data;
+ vkMapMemory(instance.GetDevice(), memory, index * size, size, 0, &data);
+ memcpy(data, indexData, size);
+ vkUnmapMemory(instance.GetDevice(), memory);
+ }
+ else
+ {
+ memcpy((char*)mappedData + index * size, indexData, size);
+ }
+ }
+
+ void Map()
+ {
+ ASSERT(mappedData == nullptr, "Mapping an already mapped buffer")
+ vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
+ }
+
+ void Unmap()
+ {
+ ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer")
+
+ vkUnmapMemory(instance.GetDevice(), memory);
+ mappedData = nullptr;
+ }
+
+ VkBuffer GetHandle() const
+ {
+ return handle;
+ }
+
+ VkDescriptorBufferInfo GetDescriptorBufferInfo(int instance)
+ {
+ VkDescriptorBufferInfo bufferInfo{};
+ bufferInfo.buffer = handle;
+ bufferInfo.offset = (VkDeviceSize)instance * size;
+ bufferInfo.range = size;
+ return bufferInfo;
+ }
+
+ VkDeviceSize GetSize() const
+ {
+ return size;
+ }
+
+ VkDeviceSize GetPosition(int index) const
+ {
+ ASSERT(index >= 0 && index < count, "Instance is outside of the buffer");
+ return size * (VkDeviceSize)index;
+ }
+
+ static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer)
+ {
+ ASSERT(srcBuffer.size == dstBuffer.size && srcBuffer.count == dstBuffer.count, "Buffers have different sizes");
+ VkCommandBufferAllocateInfo allocateInfo{};
+
+ allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocateInfo.commandPool = instance.GetCommandPool();
+ allocateInfo.commandBufferCount = 1;
+
+ VkCommandBuffer commandBuffer;
+ VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer");
+
+ VkCommandBufferBeginInfo beginInfo{};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+ vkBeginCommandBuffer(commandBuffer, &beginInfo);
+
+ VkBufferCopy bufferCopy{};
+ bufferCopy.dstOffset = 0;
+ bufferCopy.srcOffset = 0;
+ bufferCopy.size = srcBuffer.size * (VkDeviceSize)srcBuffer.count;
+
+ vkCmdCopyBuffer(commandBuffer, srcBuffer.GetHandle(), dstBuffer.GetHandle(), 1, &bufferCopy);
+
+ vkEndCommandBuffer(commandBuffer);
+
+ VkSubmitInfo submitInfo{};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
+
+ vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
+ vkQueueWaitIdle(instance.GetGraphicsQueue());
+
+ vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), 1, &commandBuffer);
+ }
+
+private:
+ static uint32_t FindMemoryType(Instance& instance, uint32_t typeFilter, VkMemoryPropertyFlags properties)
+ {
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+ vkGetPhysicalDeviceMemoryProperties(instance.GetPhysicalDevice(), &memoryProperties);
+ for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
+ {
+ if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
+ return i;
+ }
+ throw std::runtime_error("Failed to find suitable memory type");
+ }
+};
diff --git a/Vulkan/src/Common.h b/Vulkan/src/Common.h
index 986455e..20fe90a 100644
--- a/Vulkan/src/Common.h
+++ b/Vulkan/src/Common.h
@@ -1,10 +1,11 @@
#pragma once
+#include "VulkanException.h"
#include
#include
#define ASSERT(Function, message) if(!(Function)) { throw std::runtime_error(message); } while(false)
-#define VK_ASSERT(Function, message) if(Function != VK_SUCCESS) { throw std::runtime_error(message); } while(false)
+#define VK_ASSERT(Function, message) if(Function != VK_SUCCESS) { throw VulkanException(message); } while(false)
VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
diff --git a/Vulkan/src/DebugMessenger.h b/Vulkan/src/DebugMessenger.h
index 8c621fc..383f6d8 100644
--- a/Vulkan/src/DebugMessenger.h
+++ b/Vulkan/src/DebugMessenger.h
@@ -38,14 +38,14 @@ public:
DebugMessenger& operator=(DebugMessenger&&) = delete;
DebugMessenger& operator=(const DebugMessenger&) = delete;
- void AddRequiredExtensions(std::vector* extensions)
+ static void AddRequiredExtensions(std::vector* extensions)
{
#ifndef NDEBUG
extensions->emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
}
- void AddRequiredLayers(std::vector* layers)
+ static void AddRequiredLayers(std::vector* layers)
{
#ifndef NDEBUG
layers->emplace_back("VK_LAYER_KHRONOS_validation");
@@ -61,6 +61,8 @@ private:
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{
std::cerr << pCallbackData->pMessage << std::endl;
+ if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
+ throw VulkanException(pCallbackData->pMessage);
}
return VK_FALSE;
}
diff --git a/Vulkan/src/Instance.h b/Vulkan/src/Instance.h
new file mode 100644
index 0000000..24a6fe9
--- /dev/null
+++ b/Vulkan/src/Instance.h
@@ -0,0 +1,359 @@
+#pragma once
+
+#include
+#include
+
+#include "DebugMessenger.h"
+#include "QueueFamilies.h"
+#include "SwapChain.h"
+
+class Instance final
+{
+private:
+ static const int MAX_FRAMES_IN_FLIGHT = 2;
+ static const int WINDOW_WIDTH = 1920;
+ static const int WINDOW_HEIGHT = 1080;
+
+
+ VkInstance instance;
+ GLFWwindow* window;
+ VkSurfaceKHR surface;
+ std::unique_ptr debugMessenger;
+ VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+ VkDevice device;
+ VkQueue graphicsQueue;
+ VkQueue presentQueue;
+ std::unique_ptr swapChain;
+ VkCommandPool commandPool;
+ bool framebufferResized = false;
+
+public:
+ Instance(const std::string& applicationName)
+ {
+ InitializeWindow(applicationName);
+ InitializeInstance(applicationName);
+ InitializeDebugMessenger();
+ InitializeSurface();
+ SelectPhysicalDevice();
+ InitializeLogicalDevice();
+ InitializeSwapChain();
+ InitializeCommandPool();
+ }
+
+ ~Instance()
+ {
+ vkDestroyCommandPool(device, commandPool, nullptr);
+ swapChain.reset();
+ vkDestroyDevice(device, nullptr);
+ vkDestroySurfaceKHR(instance, surface, nullptr);
+ debugMessenger.reset();
+ vkDestroyInstance(instance, nullptr);
+ glfwDestroyWindow(window);
+ }
+
+ bool BeginPresent()
+ {
+ if (!swapChain->BeginPresent())
+ return true;
+ }
+
+ bool EndPresent()
+ {
+ swapChain->EndPresent(presentQueue, framebufferResized);
+ return !glfwWindowShouldClose(window);
+ }
+
+ void SubmitGraphicsQueue(const std::vector& commandBuffers)
+ {
+ VkSemaphore waitSemaphores[] = {swapChain->GetAvailableImageSemaphore()};
+ VkSemaphore signalSemaphores[] = {swapChain->GetRenderFinishedSemaphore()};
+ VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
+ VkSubmitInfo submitInfo{};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.waitSemaphoreCount = 1;
+ submitInfo.pWaitSemaphores = waitSemaphores;
+ submitInfo.pWaitDstStageMask = waitStages;
+ submitInfo.commandBufferCount = commandBuffers.size();
+ submitInfo.pCommandBuffers = commandBuffers.data();
+ submitInfo.signalSemaphoreCount = 1;
+ submitInfo.pSignalSemaphores = signalSemaphores;
+
+ VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, swapChain->GetInFlightFence()), "Failed to submit command buffer");
+ }
+
+ VkInstance GetInstance() const
+ {
+ return instance;
+ }
+
+ VkPhysicalDevice GetPhysicalDevice() const
+ {
+ return physicalDevice;
+ }
+
+ VkDevice GetDevice() const
+ {
+ return device;
+ }
+
+ VkCommandPool GetCommandPool() const
+ {
+ return commandPool;
+ }
+
+ VkQueue GetGraphicsQueue() const
+ {
+ return graphicsQueue;
+ }
+
+ int GetMaxFramesInFlight()
+ {
+ return MAX_FRAMES_IN_FLIGHT;
+ }
+
+ const SwapChain& GetSwapChain() const
+ {
+ return *swapChain;
+ }
+
+private:
+ void InitializeWindow(const std::string& applicationName)
+ {
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
+
+ glfwSetWindowUserPointer(window, this);
+ glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
+ }
+
+ void InitializeInstance(const std::string& applicationName)
+ {
+ VkApplicationInfo appInfo{};
+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appInfo.pApplicationName = applicationName.c_str();
+ appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+ appInfo.pEngineName = "Greet Engine";
+ appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ appInfo.apiVersion = VK_API_VERSION_1_1;
+
+ std::vector requiredExtensions = GetRequiredExtensions();
+
+ uint32_t extensionCount;
+ vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+ std::vector extensions{extensionCount};
+ vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
+
+ std::cout << "Supported Extensions: " << std::endl;
+ for (auto&& extension : extensions)
+ {
+ std::cout << "\t" << extension.extensionName << std::endl;
+ }
+
+ std::vector layers{};
+ DebugMessenger::AddRequiredLayers(&layers);
+ ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
+
+ VkInstanceCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ createInfo.pApplicationInfo = &appInfo;
+ createInfo.enabledExtensionCount = requiredExtensions.size();
+ createInfo.ppEnabledExtensionNames = requiredExtensions.data();
+ createInfo.enabledLayerCount = layers.size();
+ createInfo.ppEnabledLayerNames = layers.data();
+ VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
+ }
+
+ void InitializeDebugMessenger()
+ {
+ debugMessenger = std::make_unique(instance);
+ }
+
+ void InitializeSurface()
+ {
+ VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
+ }
+
+ void SelectPhysicalDevice()
+ {
+ uint32_t deviceCount;
+ vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
+ ASSERT(deviceCount != 0, "No available devices support Vulkan");
+
+ std::vector devices(deviceCount);
+ vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
+ std::cout << "Available devices: " << std::endl;
+ for (auto&& device : devices)
+ {
+ VkPhysicalDeviceProperties deviceProperties;
+ vkGetPhysicalDeviceProperties(device, &deviceProperties);
+ std::cout << "\t" << deviceProperties.deviceName << std::endl;
+ }
+ for (auto&& device : devices)
+ {
+ if (IsPhysicalDeviceSuitable(device))
+ {
+ VkPhysicalDeviceProperties deviceProperties;
+ vkGetPhysicalDeviceProperties(device, &deviceProperties);
+ physicalDevice = device;
+ std::cout << "Selecting device: " << deviceProperties.deviceName << std::endl;
+ break;
+ }
+ }
+ ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
+ }
+
+ void InitializeLogicalDevice()
+ {
+ QueueFamilies queueFamilies{surface, physicalDevice};
+
+ float queuePriority = 1.0f;
+
+ std::vector queueCreateInfos{};
+ std::set uniqueQueueFamilies{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
+ for(auto&& queueFamily : uniqueQueueFamilies)
+ {
+ VkDeviceQueueCreateInfo queueCreateInfo{};
+ queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queueCreateInfo.queueFamilyIndex = queueFamily;
+ queueCreateInfo.queueCount = 1;
+ queueCreateInfo.pQueuePriorities = &queuePriority;
+ queueCreateInfos.emplace_back(queueCreateInfo);
+ }
+ std::vector deviceExtensions = GetRequiredDeviceExtensions();
+ VkPhysicalDeviceFeatures deviceFeatures{};
+ deviceFeatures.fillModeNonSolid = VK_TRUE;
+ VkDeviceCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ createInfo.pQueueCreateInfos = queueCreateInfos.data();
+ createInfo.queueCreateInfoCount = queueCreateInfos.size();
+ createInfo.pEnabledFeatures = &deviceFeatures;
+ createInfo.ppEnabledExtensionNames = deviceExtensions.data();
+ createInfo.enabledExtensionCount = deviceExtensions.size();
+
+ VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
+
+ vkGetDeviceQueue(device, queueFamilies.graphicsFamily.value(), 0, &graphicsQueue);
+ vkGetDeviceQueue(device, queueFamilies.presentFamily.value(), 0, &presentQueue);
+ }
+
+ void InitializeSwapChain()
+ {
+ swapChain = std::make_unique(window, surface, device, physicalDevice);
+ }
+
+ void InitializeCommandPool()
+ {
+ QueueFamilies queueFamilies{surface, physicalDevice};
+
+ VkCommandPoolCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+ createInfo.queueFamilyIndex = queueFamilies.graphicsFamily.value();
+ VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
+ }
+
+ std::vector GetRequiredExtensions()
+ {
+ uint32_t glfwExtensionCount;
+ const char** glfwExtensions;
+ glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
+
+ std::vector extensions{glfwExtensions, glfwExtensions + glfwExtensionCount};
+
+ debugMessenger->AddRequiredExtensions(&extensions);
+
+ return extensions;
+ }
+
+ bool CheckLayerSupport(const std::vector& layers)
+ {
+ uint32_t layerCount;
+ vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
+
+ std::vector availableLayers(layerCount);
+ vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
+
+ std::cout << "Supported Layers: " << std::endl;
+ for (auto&& availableLayer : availableLayers)
+ {
+ std::cout << "\t" << availableLayer.layerName << std::endl;
+ }
+
+ for (auto&& layer : layers)
+ {
+ bool layerFound = false;
+ for (auto&& availableLayer : availableLayers)
+ {
+ if (std::strcmp(layer, availableLayer.layerName) == 0)
+ {
+ layerFound = true;
+ break;
+ }
+ }
+ if (!layerFound)
+ return false;
+ }
+ return true;
+ }
+
+ bool IsPhysicalDeviceSuitable(VkPhysicalDevice device)
+ {
+ VkPhysicalDeviceProperties deviceProperties;
+ vkGetPhysicalDeviceProperties(device, &deviceProperties);
+ if (deviceProperties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
+ return false;
+
+ VkPhysicalDeviceFeatures deviceFeatures;
+ vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
+ if (!deviceFeatures.fillModeNonSolid)
+ return false;
+
+ QueueFamilies queueFamilies{surface, device};
+ if (!queueFamilies.AllRequiredFamiliesSupported())
+ return false;
+
+ if (!CheckDeviceExtensionSupport(device))
+ return false;
+ SwapChainSupportDetails details{surface, device};
+ if (!details.Valid())
+ return false;
+
+ return true;
+ }
+
+ bool CheckDeviceExtensionSupport(VkPhysicalDevice device)
+ {
+ uint32_t extensionCount;
+ vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
+ std::vector extensions{extensionCount};
+ vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data());
+
+ for (auto&& requiredExtension : GetRequiredDeviceExtensions())
+ {
+ bool found = false;
+ for (auto&& extension : extensions)
+ {
+ if (std::strcmp(requiredExtension, extension.extensionName) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+ return true;
+ }
+
+ std::vector GetRequiredDeviceExtensions()
+ {
+ return {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
+ }
+
+ static void FramebufferResizeCallback(GLFWwindow* window, int width, int height)
+ {
+ Instance* instance = static_cast(glfwGetWindowUserPointer(window));
+ instance->framebufferResized = true;
+ }
+
+};
diff --git a/Vulkan/src/QueueFamilies.h b/Vulkan/src/QueueFamilies.h
new file mode 100644
index 0000000..6a61f6c
--- /dev/null
+++ b/Vulkan/src/QueueFamilies.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include
+#include
+#include
+
+struct QueueFamilies
+{
+ std::optional graphicsFamily;
+ std::optional presentFamily;
+
+ QueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device)
+ {
+ uint32_t queueFamilyCount = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
+ std::vector queueFamilies(queueFamilyCount);
+ vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
+
+ int i = 0;
+ for (auto&& queueFamily : queueFamilies)
+ {
+ if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
+ {
+ graphicsFamily = i;
+ }
+ VkBool32 presentSupport = false;
+ vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
+ if (presentSupport)
+ {
+ presentFamily = i;
+ }
+ i++;
+ }
+
+ }
+
+ bool AllRequiredFamiliesSupported()
+ {
+ return graphicsFamily.has_value() && presentFamily.has_value();
+ }
+};
diff --git a/Vulkan/src/SwapChain.h b/Vulkan/src/SwapChain.h
index 9d865c0..6b342bd 100644
--- a/Vulkan/src/SwapChain.h
+++ b/Vulkan/src/SwapChain.h
@@ -1,20 +1,406 @@
#pragma once
+#include "QueueFamilies.h"
+#include
#include
#include
+struct SwapChainSupportDetails
+{
+ VkSurfaceCapabilitiesKHR capabilities;
+ std::vector formats;
+ std::vector presentModes;
+
+ SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice device)
+ {
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities);
+
+ uint32_t formatCount;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
+ if (formatCount != 0)
+ {
+ formats.resize(formatCount);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, formats.data());
+ }
+
+ uint32_t presentModeCount;
+ vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
+ if (presentModeCount != 0)
+ {
+ presentModes.resize(presentModeCount);
+ vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data());
+ }
+ }
+
+ bool Valid()
+ {
+ return !formats.empty() && !presentModes.empty();
+ }
+};
+
class SwapChain
{
- VkSwapchainKHR swapChain;
- VkFormat swapChainImageFormat;
- VkExtent2D swapChainExtent;
- std::vector swapChainImageViews;
- std::vector swapChainImages;
- std::vector swapChainFramebuffers;
+ // TODO: Remove, replaced by Instance::MAX_FRAMES_IN_FLIGHT
+ static const int MAX_FRAMES_IN_FLIGHT = 2;
- SwapChain()
+ // Needed for recreation and destruction
+ GLFWwindow* window;
+ VkSurfaceKHR surface;
+ VkPhysicalDevice physicalDevice;
+ VkDevice device;
+
+ // Created by the class
+ VkSwapchainKHR handle;
+ VkRenderPass renderPass;
+ VkFormat imageFormat;
+ VkExtent2D extent;
+ std::vector imageViews;
+ std::vector images;
+ std::vector framebuffers;
+
+ int flightIndex;
+ uint32_t imageIndex;
+ std::vector imageAvailableSemaphores;
+ std::vector renderFinishedSemaphores;
+ std::vector inFlightFences;
+
+public:
+ SwapChain(GLFWwindow* window, VkSurfaceKHR surface, VkDevice device, VkPhysicalDevice physicalDevice)
+ : window{window}, surface{surface}, physicalDevice{physicalDevice}, device{device}
{
-
+ Initialize();
+ InitializeImageViews();
+ InitializeRenderPass();
+ InitializeFramebuffers();
+ InitializeSyncObjects();
}
+ ~SwapChain()
+ {
+ for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
+ {
+ vkDestroyFence(device, inFlightFences[i], nullptr);
+ vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
+ vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
+ }
+ Destroy();
+ vkDestroyRenderPass(device, renderPass, nullptr);
+ }
+
+ VkSwapchainKHR GetHandle() const
+ {
+ return handle;
+ }
+
+ VkRenderPass GetRenderPass() const
+ {
+ return renderPass;
+ }
+
+ VkExtent2D GetExtent() const
+ {
+ return extent;
+ }
+
+ VkFramebuffer GetFramebuffer() const
+ {
+ return framebuffers[imageIndex];
+ }
+
+ bool BeginPresent()
+ {
+ vkWaitForFences(device, 1, &inFlightFences[flightIndex], VK_TRUE, UINT64_MAX);
+
+ VkResult result = vkAcquireNextImageKHR(device, handle, UINT64_MAX, imageAvailableSemaphores[flightIndex], VK_NULL_HANDLE, &imageIndex);
+ if (result == VK_ERROR_OUT_OF_DATE_KHR)
+ {
+ Recreate();
+ return false;
+ }
+
+ vkResetFences(device, 1, &inFlightFences[flightIndex]);
+ return true;
+ }
+
+ void EndPresent(VkQueue presentQueue, bool framebufferResized)
+ {
+ VkSwapchainKHR swapChains[] = {handle};
+ VkPresentInfoKHR presentInfo{};
+ presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ presentInfo.waitSemaphoreCount = 1;
+ presentInfo.pWaitSemaphores = &renderFinishedSemaphores[flightIndex];
+ presentInfo.swapchainCount = 1;
+ presentInfo.pSwapchains = &handle;
+ presentInfo.pImageIndices = &imageIndex;
+ presentInfo.pResults = nullptr;
+
+ VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
+ if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
+ {
+ framebufferResized = false;
+ Recreate();
+ }
+
+ flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
+ }
+
+ int GetFlightIndex() const
+ {
+ return flightIndex;
+ }
+
+ int GetMaxFramesInFlight() const
+ {
+ return MAX_FRAMES_IN_FLIGHT;
+ }
+
+ VkFence GetInFlightFence() const
+ {
+ return inFlightFences[flightIndex];
+ }
+
+ VkSemaphore GetAvailableImageSemaphore() const
+ {
+ return imageAvailableSemaphores[flightIndex];
+ }
+
+ VkSemaphore GetRenderFinishedSemaphore() const
+ {
+ return renderFinishedSemaphores[flightIndex];
+ }
+
+
+ void Recreate()
+ {
+ int width = 0;
+ int height = 0;
+ glfwGetFramebufferSize(window, &width, &height);
+ while (width == 0 || height == 0)
+ {
+ glfwGetFramebufferSize(window, &width, &height);
+ glfwWaitEvents();
+ }
+
+ vkDeviceWaitIdle(device);
+
+ Destroy();
+
+ Initialize();
+ InitializeImageViews();
+ InitializeFramebuffers();
+ }
+
+private:
+
+ void Initialize()
+ {
+ SwapChainSupportDetails swapChainSupport{surface, physicalDevice};
+
+ VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
+ VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
+ extent = SelectSwapExtent(window, swapChainSupport.capabilities);
+ imageFormat = format.format;
+ uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
+ if (swapChainSupport.capabilities.maxImageCount != 0)
+ {
+ imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
+ }
+
+ QueueFamilies queueFamilies{surface, physicalDevice};
+ std::vector queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
+
+ VkSwapchainCreateInfoKHR createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ createInfo.surface = surface;
+ createInfo.minImageCount = imageCount;
+ createInfo.imageFormat = format.format;
+ createInfo.imageColorSpace = format.colorSpace;
+ createInfo.imageExtent = extent;
+ createInfo.imageArrayLayers = 1;
+ createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
+ createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ createInfo.presentMode = presentMode;
+ createInfo.clipped = VK_TRUE;
+ createInfo.oldSwapchain = VK_NULL_HANDLE;
+ if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
+ {
+ createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+ createInfo.queueFamilyIndexCount = 2;
+ createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
+ }
+ else
+ {
+ createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ createInfo.queueFamilyIndexCount = 0;
+ createInfo.pQueueFamilyIndices = nullptr;
+ }
+
+ VK_ASSERT(vkCreateSwapchainKHR(device, &createInfo, nullptr, &handle), "Failed to initialize the swapchain");
+
+ vkGetSwapchainImagesKHR(device, handle, &imageCount, nullptr);
+ images.resize(imageCount);
+ vkGetSwapchainImagesKHR(device, handle, &imageCount, images.data());
+ }
+
+ void InitializeImageViews()
+ {
+ imageViews.resize(images.size());
+ for (size_t i = 0; i < images.size(); i++)
+ {
+ VkImageViewCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ createInfo.image = images[i];
+ createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ createInfo.format = imageFormat;
+ createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ createInfo.subresourceRange.baseMipLevel = 0;
+ createInfo.subresourceRange.levelCount = 1;
+ createInfo.subresourceRange.baseArrayLayer = 0;
+ createInfo.subresourceRange.layerCount = 1;
+ VK_ASSERT(vkCreateImageView(device, &createInfo, nullptr, &imageViews[i]), "Failed to initialize swapchain image view");
+ }
+ }
+
+ void InitializeRenderPass()
+ {
+ VkAttachmentDescription colorAttachment{};
+ colorAttachment.format = imageFormat;
+ colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ VkAttachmentReference colorAttachmentRef{};
+ colorAttachmentRef.attachment = 0;
+ colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass{};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &colorAttachmentRef;
+
+ VkSubpassDependency dependency{};
+ dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+ dependency.dstSubpass = 0;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcAccessMask = 0;
+ dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ VkRenderPassCreateInfo renderPassCreateInfo{};
+ renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ renderPassCreateInfo.attachmentCount = 1;
+ renderPassCreateInfo.pAttachments = &colorAttachment;
+ renderPassCreateInfo.subpassCount = 1;
+ renderPassCreateInfo.pSubpasses = &subpass;
+ renderPassCreateInfo.dependencyCount = 1;
+ renderPassCreateInfo.pDependencies = &dependency;
+
+ VK_ASSERT(vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
+ }
+
+ void InitializeFramebuffers()
+ {
+ framebuffers.resize(images.size());
+
+ for (size_t i = 0; i < imageViews.size(); ++i)
+ {
+ VkImageView attachments[] = {imageViews[i]};
+
+ VkFramebufferCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ createInfo.renderPass = renderPass;
+ createInfo.attachmentCount = 1;
+ createInfo.pAttachments = attachments;
+ createInfo.width = extent.width;
+ createInfo.height = extent.height;
+ createInfo.layers = 1;
+
+ VK_ASSERT(vkCreateFramebuffer(device, &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer");
+ }
+ }
+
+ void InitializeSyncObjects()
+ {
+ imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
+ renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
+ inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
+ VkSemaphoreCreateInfo semaphoreCreateInfo{};
+ semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
+ {
+ VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
+ VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
+
+ VkFenceCreateInfo fenceCreateInfo{};
+ fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+ VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
+ }
+ }
+
+ void Destroy()
+ {
+ for (auto&& framebuffer : framebuffers)
+ {
+ vkDestroyFramebuffer(device, framebuffer, nullptr);
+ }
+ for (auto&& swapChainImageView : imageViews)
+ {
+ vkDestroyImageView(device, swapChainImageView, nullptr);
+ }
+ vkDestroySwapchainKHR(device, handle, nullptr);
+ }
+
+ VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector& availableFormats)
+ {
+ for (auto&& availableFormat : availableFormats)
+ {
+ if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
+ {
+ return availableFormat;
+ }
+ }
+ return availableFormats[0];
+ }
+
+ VkPresentModeKHR SelectSwapPresentMode(const std::vector& availablePresentModes)
+ {
+ for (auto&& availablePresentMode : availablePresentModes)
+ {
+ if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
+ {
+ return availablePresentMode;
+ }
+ }
+
+ // VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
+ return VK_PRESENT_MODE_FIFO_KHR;
+ }
+
+ VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
+ {
+ if (capabilities.currentExtent.width != std::numeric_limits::max())
+ return capabilities.currentExtent;
+
+ int width, height;
+ glfwGetFramebufferSize(window, &width, &height);
+
+ VkExtent2D extent{width, height};
+ extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
+ extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
+ return extent;
+ }
+
+
};
diff --git a/Vulkan/src/VulkanException.h b/Vulkan/src/VulkanException.h
new file mode 100644
index 0000000..1007e85
--- /dev/null
+++ b/Vulkan/src/VulkanException.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+
+class VulkanException : public std::runtime_error
+{
+public:
+ VulkanException(const char* str)
+ : runtime_error{str}
+ {}
+};
diff --git a/Vulkan/src/Window.h b/Vulkan/src/Window.h
new file mode 100644
index 0000000..a27107a
--- /dev/null
+++ b/Vulkan/src/Window.h
@@ -0,0 +1,6 @@
+#pragma once
+
+class Window
+{
+
+};
diff --git a/Vulkan/src/main.cpp b/Vulkan/src/main.cpp
index 303c287..515b819 100644
--- a/Vulkan/src/main.cpp
+++ b/Vulkan/src/main.cpp
@@ -1,6 +1,7 @@
-#include "DebugMessenger.h"
#include "FileSystem.h"
-
+#include "Buffer.h"
+#include "Instance.h"
+#define GLM_FORCE_LEFT_HANDED
#define GLFW_INCLUDE_VULKAN
#include
@@ -11,73 +12,101 @@
#include
#include
#include
+#include
+#include
+#include
-static const int WINDOW_WIDTH = 1920;
-static const int WINDOW_HEIGHT = 1080;
-static const int MAX_FRAMES_IN_FLIGHT = 2;
-
-struct QueueFamilyIndices
-{
- std::optional graphicsFamily;
- std::optional presentFamily;
-
- bool AllRequiredFamiliesSupported()
+struct Vertex {
+ glm::vec2 pos;
+ glm::vec3 color;
+
+ static VkVertexInputBindingDescription getBindingDescription()
{
- return graphicsFamily.has_value() && presentFamily.has_value();
+ VkVertexInputBindingDescription description{};
+
+ description.binding = 0;
+ description.stride = sizeof(Vertex);
+ description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ return description;
+ }
+
+ static std::vector getAttributeDescriptions()
+ {
+ std::vector descriptions{2};
+
+ descriptions[0].binding = 0;
+ descriptions[0].location = 0;
+ descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
+ descriptions[0].offset = offsetof(Vertex, pos);
+
+ descriptions[1].binding = 0;
+ descriptions[1].location = 1;
+ descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
+ descriptions[1].offset = offsetof(Vertex, color);
+
+ return descriptions;
}
};
-struct SwapChainSupportDetails
-{
- VkSurfaceCapabilitiesKHR capabilities;
- std::vector formats;
- std::vector presentModes;
+const std::vector vertices = {
+ Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
+ Vertex{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
+ Vertex{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
+ Vertex{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
+};
- bool Valid()
- {
- return !formats.empty() && !presentModes.empty();
- }
+const std::vector indices = {
+ 0, 1, 2, 2, 3, 0
+};
+
+struct UniformBufferObject
+{
+ glm::mat4 model;
+ glm::mat4 view;
+ glm::mat4 projection;
};
class Application final
{
private:
- GLFWwindow* window;
- VkInstance instance;
- VkSurfaceKHR surface;
- DebugMessenger* debugMessenger;
- VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
- VkDevice device;
- VkQueue graphicsQueue;
- VkQueue presentQueue;
- VkSwapchainKHR swapChain;
- VkFormat swapChainImageFormat;
- VkExtent2D swapChainExtent;
- std::vector swapChainImageViews;
- std::vector swapChainImages;
- std::vector swapChainFramebuffers;
+ std::unique_ptr instance;
+ VkDescriptorSetLayout uniformBufferLayout;
+ VkDescriptorPool descriptorPool;
+ std::vector descriptorSets;
VkPipelineLayout pipelineLayout;
- VkRenderPass renderPass;
VkPipeline graphicsPipeline;
- VkCommandPool commandPool;
+ std::unique_ptr vertexBuffer;
+ std::unique_ptr indexBuffer;
+ std::unique_ptr uniformBuffer;
std::vector commandBuffers;
- std::vector imageAvailableSemaphores;
- std::vector renderFinishedSemaphores;
- std::vector inFlightFences;
- int currentFrame = 0;
- bool framebufferResized = false;
+ UniformBufferObject uniformBufferObject;
public:
Application()
{
- InitializeWindow();
- InitializeVulkan();
+ instance = std::make_unique("Vulkan Tutorial");
+ InitializeUniformBufferLayout();
+ InitializeGraphicsPipeline();
+ InitializeVertexBuffer();
+ InitializeIndexBuffer();
+ InitializeUniformBuffer();
+ InitializeDescriptorPool();
+ InitializeDescriptorSet();
+ InitializeCommandBuffer();
}
~Application()
{
- DestroyVulkan();
- DestroyWindow();
+ vkDeviceWaitIdle(instance->GetDevice());
+ uniformBuffer.reset();
+ vertexBuffer.reset();
+ indexBuffer.reset();
+ vkDestroyPipeline(instance->GetDevice(), graphicsPipeline, nullptr);
+ vkDestroyPipelineLayout(instance->GetDevice(), pipelineLayout, nullptr);
+ vkDestroyDescriptorPool(instance->GetDevice(), descriptorPool, nullptr);
+ vkDestroyDescriptorSetLayout(instance->GetDevice(), uniformBufferLayout, nullptr);
+ instance.reset();
}
Application(Application&&) = delete;
@@ -87,306 +116,76 @@ public:
bool Update()
{
- vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
-
- uint32_t imageIndex;
- VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
- if (result == VK_ERROR_OUT_OF_DATE_KHR)
- {
- RecreateSwapChain();
+ if (!instance->BeginPresent())
return true;
- }
- vkResetFences(device, 1, &inFlightFences[currentFrame]);
+ RecordCommandBuffer(commandBuffers[instance->GetSwapChain().GetFlightIndex()]);
- RecordCommandBuffer(commandBuffers[currentFrame], imageIndex);
- VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
- VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
- VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
- VkSubmitInfo submitInfo{};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = waitSemaphores;
- submitInfo.pWaitDstStageMask = waitStages;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffers[currentFrame];
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = signalSemaphores;
-
- VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]), "Failed to submit command buffer");
-
- VkSwapchainKHR swapChains[] = {swapChain};
- VkPresentInfoKHR presentInfo{};
- presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- presentInfo.waitSemaphoreCount = 1;
- presentInfo.pWaitSemaphores = signalSemaphores;
- presentInfo.swapchainCount = 1;
- presentInfo.pSwapchains = swapChains;
- presentInfo.pImageIndices = &imageIndex;
- presentInfo.pResults = nullptr;
-
- result = vkQueuePresentKHR(presentQueue, &presentInfo);
- if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
- {
- framebufferResized = false;
- RecreateSwapChain();
- }
-
- currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
- return !glfwWindowShouldClose(window);
+ instance->SubmitGraphicsQueue(std::vector{commandBuffers[instance->GetSwapChain().GetFlightIndex()]});
+ return instance->EndPresent();
}
private:
- void InitializeWindow()
- {
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Vulkan Window", nullptr, nullptr);
- glfwSetWindowUserPointer(window, this);
- glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
+ void InitializeUniformBufferLayout()
+ {
+ VkDescriptorSetLayoutBinding layoutBinding{};
+ layoutBinding.binding = 0;
+ layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ layoutBinding.descriptorCount = 1;
+ layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ layoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ createInfo.bindingCount = 1;
+ createInfo.pBindings = &layoutBinding;
+
+ VK_ASSERT(vkCreateDescriptorSetLayout(instance->GetDevice(), &createInfo, nullptr, &uniformBufferLayout), "Failed to initialize uniform buffer layout");
}
- void InitializeVulkan()
+ void InitializeDescriptorPool()
{
- InitializeInstance();
- InitializeDebugMessenger();
- InitializeSurface();
- SelectPhysicalDevice();
- InitializeLogicalDevice();
- InitializeSwapChain();
- InitializeSwapChainImageViews();
- InitializeRenderPass();
- InitializeGraphicsPipeline();
- InitializeSwapChainFramebuffers();
- InitializeCommandPool();
- InitializeCommandBuffer();
- InitializeSyncObjects();
+ VkDescriptorPoolSize poolSize{};
+ poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ poolSize.descriptorCount = instance->GetMaxFramesInFlight();
+
+ VkDescriptorPoolCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ createInfo.poolSizeCount = 1;
+ createInfo.pPoolSizes = &poolSize;
+ createInfo.maxSets = instance->GetMaxFramesInFlight();
+
+ VK_ASSERT(vkCreateDescriptorPool(instance->GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
}
- void InitializeInstance()
+ void InitializeDescriptorSet()
{
- VkApplicationInfo appInfo{};
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.pApplicationName = "Vulkan Tutorial";
- appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.pEngineName = "Greet Engine";
- appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.apiVersion = VK_API_VERSION_1_1;
+ std::vector layouts{static_cast(instance->GetMaxFramesInFlight()), uniformBufferLayout};
+ VkDescriptorSetAllocateInfo allocateInfo{};
+ allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocateInfo.descriptorPool = descriptorPool;
+ allocateInfo.descriptorSetCount = instance->GetMaxFramesInFlight();
+ allocateInfo.pSetLayouts = layouts.data();
- std::vector requiredExtensions = GetRequiredExtensions();
+ descriptorSets.resize(instance->GetMaxFramesInFlight());
+ VK_ASSERT(vkAllocateDescriptorSets(instance->GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
+ for (size_t i = 0; i < instance->GetMaxFramesInFlight(); ++i) {
+ VkDescriptorBufferInfo bufferInfo = uniformBuffer->GetDescriptorBufferInfo(i);
- uint32_t extensionCount;
- vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
- std::vector extensions{extensionCount};
- vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
+ VkWriteDescriptorSet descriptorWrite{};
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.dstSet = descriptorSets[i];
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.pBufferInfo = &bufferInfo;
+ descriptorWrite.pImageInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+ vkUpdateDescriptorSets(instance->GetDevice(), 1, &descriptorWrite, 0, nullptr);
+ }
- std::cout << "Supported Extensions: " << std::endl;
- for (auto&& extension : extensions)
- {
- std::cout << "\t" << extension.extensionName << std::endl;
- }
-
- std::vector layers{};
- debugMessenger->AddRequiredLayers(&layers);
- ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
-
- VkInstanceCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- createInfo.pApplicationInfo = &appInfo;
- createInfo.enabledExtensionCount = requiredExtensions.size();
- createInfo.ppEnabledExtensionNames = requiredExtensions.data();
- createInfo.enabledLayerCount = layers.size();
- createInfo.ppEnabledLayerNames = layers.data();
- VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
- }
-
- void InitializeDebugMessenger()
- {
- debugMessenger = new DebugMessenger(instance);
- }
-
- void InitializeSurface()
- {
- VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
- }
-
- void SelectPhysicalDevice()
- {
- uint32_t deviceCount;
- vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
- ASSERT(deviceCount != 0, "No available devices support Vulkan");
-
- std::vector devices(deviceCount);
- vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
- std::cout << "Available devices: " << std::endl;
- for (auto&& device : devices)
- {
- VkPhysicalDeviceProperties deviceProperties;
- vkGetPhysicalDeviceProperties(device, &deviceProperties);
- std::cout << "\t" << deviceProperties.deviceName << std::endl;
- }
- for (auto&& device : devices)
- {
- if (IsPhysicalDeviceSuitable(device))
- {
- VkPhysicalDeviceProperties deviceProperties;
- vkGetPhysicalDeviceProperties(device, &deviceProperties);
- physicalDevice = device;
- std::cout << "Selecting device: " << deviceProperties.deviceName << std::endl;
- break;
- }
- }
- ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
- }
-
- void InitializeLogicalDevice()
- {
- QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
-
- float queuePriority = 1.0f;
-
- std::vector queueCreateInfos{};
- std::set uniqueQueueFamilies{indices.graphicsFamily.value(), indices.presentFamily.value()};
- for(auto&& queueFamily : uniqueQueueFamilies)
- {
- VkDeviceQueueCreateInfo queueCreateInfo{};
- queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queueCreateInfo.queueFamilyIndex = queueFamily;
- queueCreateInfo.queueCount = 1;
- queueCreateInfo.pQueuePriorities = &queuePriority;
- queueCreateInfos.emplace_back(queueCreateInfo);
- }
- std::vector deviceExtensions = GetRequiredDeviceExtensions();
- VkPhysicalDeviceFeatures deviceFeatures{};
- deviceFeatures.fillModeNonSolid = VK_TRUE;
- VkDeviceCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- createInfo.pQueueCreateInfos = queueCreateInfos.data();
- createInfo.queueCreateInfoCount = queueCreateInfos.size();
- createInfo.pEnabledFeatures = &deviceFeatures;
- createInfo.ppEnabledExtensionNames = deviceExtensions.data();
- createInfo.enabledExtensionCount = deviceExtensions.size();
-
- VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
-
- vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
- vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
- }
-
- void InitializeSwapChain()
- {
- SwapChainSupportDetails swapChainSupport = FindSwapChainSupport(physicalDevice);
-
- VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
- VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
- swapChainExtent = SelectSwapExtent(swapChainSupport.capabilities);
- swapChainImageFormat = format.format;
- uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
- if (swapChainSupport.capabilities.maxImageCount != 0)
- {
- imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
- }
-
- QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
- std::vector queueFamilyIndices{indices.graphicsFamily.value(), indices.presentFamily.value()};
-
- VkSwapchainCreateInfoKHR createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- createInfo.surface = surface;
- createInfo.minImageCount = imageCount;
- createInfo.imageFormat = format.format;
- createInfo.imageColorSpace = format.colorSpace;
- createInfo.imageExtent = swapChainExtent;
- createInfo.imageArrayLayers = 1;
- createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
- createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- createInfo.presentMode = presentMode;
- createInfo.clipped = VK_TRUE;
- createInfo.oldSwapchain = VK_NULL_HANDLE;
- if (indices.graphicsFamily != indices.presentFamily)
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- createInfo.queueFamilyIndexCount = 2;
- createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
- }
- else
- {
- createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- createInfo.queueFamilyIndexCount = 0;
- createInfo.pQueueFamilyIndices = nullptr;
- }
-
- VK_ASSERT(vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain), "Failed to initialize the swapchain");
-
- vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
- swapChainImages.resize(imageCount);
- vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
- }
-
- void InitializeSwapChainImageViews()
- {
- swapChainImageViews.resize(swapChainImages.size());
- for (size_t i = 0; i < swapChainImages.size(); i++)
- {
- VkImageViewCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- createInfo.image = swapChainImages[i];
- createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- createInfo.format = swapChainImageFormat;
- createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
- createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- createInfo.subresourceRange.baseMipLevel = 0;
- createInfo.subresourceRange.levelCount = 1;
- createInfo.subresourceRange.baseArrayLayer = 0;
- createInfo.subresourceRange.layerCount = 1;
- VK_ASSERT(vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]), "Failed to initialize swapchain image view");
- }
- }
-
- void InitializeRenderPass()
- {
- VkAttachmentDescription colorAttachment{};
- colorAttachment.format = swapChainImageFormat;
- colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
- colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- VkAttachmentReference colorAttachmentRef{};
- colorAttachmentRef.attachment = 0;
- colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- VkSubpassDescription subpass{};
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.colorAttachmentCount = 1;
- subpass.pColorAttachments = &colorAttachmentRef;
-
- VkSubpassDependency dependency{};
- dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
- dependency.dstSubpass = 0;
- dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.srcAccessMask = 0;
- dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
- VkRenderPassCreateInfo renderPassCreateInfo{};
- renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassCreateInfo.attachmentCount = 1;
- renderPassCreateInfo.pAttachments = &colorAttachment;
- renderPassCreateInfo.subpassCount = 1;
- renderPassCreateInfo.pSubpasses = &subpass;
- renderPassCreateInfo.dependencyCount = 1;
- renderPassCreateInfo.pDependencies = &dependency;
-
- VK_ASSERT(vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
}
void InitializeGraphicsPipeline()
@@ -410,12 +209,15 @@ private:
shaderStages[1].module = fragShaderModule;
shaderStages[1].pName = "main";
+ VkVertexInputBindingDescription bindingDescriptions{Vertex::getBindingDescription()};
+ std::vector attributeDescriptions{Vertex::getAttributeDescriptions()};
+
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertexInputCreateInfo.vertexBindingDescriptionCount = 0;
- vertexInputCreateInfo.pVertexBindingDescriptions = nullptr;
- vertexInputCreateInfo.vertexAttributeDescriptionCount = 0;
- vertexInputCreateInfo.pVertexAttributeDescriptions = nullptr;
+ vertexInputCreateInfo.vertexBindingDescriptionCount = 1;
+ vertexInputCreateInfo.pVertexBindingDescriptions = &bindingDescriptions;
+ vertexInputCreateInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
+ vertexInputCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
@@ -425,14 +227,14 @@ private:
VkViewport viewport{};
viewport.x = 0;
viewport.y = 0;
- viewport.width = swapChainExtent.width;
- viewport.height = swapChainExtent.height;
+ viewport.width = instance->GetSwapChain().GetExtent().width;
+ viewport.height = instance->GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
- scissor.extent = swapChainExtent;
+ scissor.extent = instance->GetSwapChain().GetExtent();
std::vector dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT,
@@ -500,12 +302,12 @@ private:
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.setLayoutCount = 0;
- pipelineLayoutCreateInfo.pSetLayouts = nullptr;
+ pipelineLayoutCreateInfo.setLayoutCount = 1;
+ pipelineLayoutCreateInfo.pSetLayouts = &uniformBufferLayout;
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
- VK_ASSERT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
+ VK_ASSERT(vkCreatePipelineLayout(instance->GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
@@ -520,83 +322,59 @@ private:
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = pipelineLayout;
- graphicsPipelineCreateInfo.renderPass = renderPass;
+ graphicsPipelineCreateInfo.renderPass = instance->GetSwapChain().GetRenderPass();
graphicsPipelineCreateInfo.subpass = 0;
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
graphicsPipelineCreateInfo.basePipelineIndex = -1;
- VK_ASSERT(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
+ VK_ASSERT(vkCreateGraphicsPipelines(instance->GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
- vkDestroyShaderModule(device, vertShaderModule, nullptr);
- vkDestroyShaderModule(device, fragShaderModule, nullptr);
+ vkDestroyShaderModule(instance->GetDevice(), vertShaderModule, nullptr);
+ vkDestroyShaderModule(instance->GetDevice(), fragShaderModule, nullptr);
}
- void InitializeSwapChainFramebuffers()
+ void InitializeVertexBuffer()
{
- swapChainFramebuffers.resize(swapChainImages.size());
+ VkDeviceSize bufferSize = sizeof(Vertex) * vertices.size();
+ Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
- for (size_t i = 0; i < swapChainImageViews.size(); ++i)
- {
- VkImageView attachments[] = {swapChainImageViews[i]};
+ stagingBuffer.Update((void*)vertices.data(), 0);
- VkFramebufferCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- createInfo.renderPass = renderPass;
- createInfo.attachmentCount = 1;
- createInfo.pAttachments = attachments;
- createInfo.width = swapChainExtent.width;
- createInfo.height = swapChainExtent.height;
- createInfo.layers = 1;
+ vertexBuffer = std::make_unique(*instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bufferSize, 1);
+ Buffer::CopyBuffer(*instance, stagingBuffer, *vertexBuffer);
+ }
- VK_ASSERT(vkCreateFramebuffer(device, &createInfo, nullptr, &swapChainFramebuffers[i]), "Failed to initialize swap chain framebuffer");
- }
- }
-
- void InitializeCommandPool()
+ void InitializeIndexBuffer()
{
- QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
+ VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size();
+ Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
- VkCommandPoolCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- createInfo.queueFamilyIndex = indices.graphicsFamily.value();
- VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
+ stagingBuffer.Update((void*)indices.data(), 0);
+ indexBuffer = std::make_unique(*instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bufferSize, 1);
+ Buffer::CopyBuffer(*instance, stagingBuffer, *indexBuffer);
+ }
+
+ void InitializeUniformBuffer()
+ {
+ VkDeviceSize bufferSize = sizeof(UniformBufferObject) * instance->GetMaxFramesInFlight();
+ uniformBuffer = std::make_unique(*instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, instance->GetMaxFramesInFlight());
+ uniformBuffer->Map();
}
void InitializeCommandBuffer()
{
- commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
+ commandBuffers.resize(instance->GetMaxFramesInFlight());
VkCommandBufferAllocateInfo allocateInfo{};
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocateInfo.commandPool = commandPool;
+ allocateInfo.commandPool = instance->GetCommandPool();
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandBufferCount = commandBuffers.size();
- VK_ASSERT(vkAllocateCommandBuffers(device, &allocateInfo, commandBuffers.data()), "Failed to initialize command buffer");
+ VK_ASSERT(vkAllocateCommandBuffers(instance->GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to initialize command buffer");
}
- void InitializeSyncObjects()
- {
- imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
- renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
- inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
- VkSemaphoreCreateInfo semaphoreCreateInfo{};
- semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
- {
- VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
- VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
-
- VkFenceCreateInfo fenceCreateInfo{};
- fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
- }
- }
-
- void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex)
+ void RecordCommandBuffer(VkCommandBuffer commandBuffer)
{
vkResetCommandBuffer(commandBuffer, 0);
@@ -611,35 +389,57 @@ private:
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassBeginInfo.renderPass = renderPass;
- renderPassBeginInfo.framebuffer = swapChainFramebuffers[imageIndex];
+ renderPassBeginInfo.renderPass = instance->GetSwapChain().GetRenderPass();
+ renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
renderPassBeginInfo.renderArea.offset = {0, 0};
- renderPassBeginInfo.renderArea.extent = swapChainExtent;
+ renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
+ UpdateUniformBuffer();
+
+ VkBuffer vbo = vertexBuffer->GetHandle();
+ VkDeviceSize offset = 0;
+ vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vbo, &offset);
+ vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetHandle(), 0, VK_INDEX_TYPE_UINT16);
+
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
- viewport.width = swapChainExtent.width;
- viewport.height = swapChainExtent.height;
+ viewport.width = instance->GetSwapChain().GetExtent().width;
+ viewport.height = instance->GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
- scissor.extent = swapChainExtent;
+ scissor.extent = instance->GetSwapChain().GetExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
- vkCmdDraw(commandBuffer, 3, 1, 0, 0);
+ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[instance->GetSwapChain().GetFlightIndex()], 0, nullptr);
+ vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffer);
VK_ASSERT(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer");
}
+ void UpdateUniformBuffer()
+ {
+ static auto startTime = std::chrono::high_resolution_clock::now();
+
+ auto currentTime = std::chrono::high_resolution_clock::now();
+ float time = std::chrono::duration(currentTime - startTime).count();
+ uniformBufferObject.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
+ uniformBufferObject.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
+ uniformBufferObject.projection = glm::perspective(glm::radians(45.0f), instance->GetSwapChain().GetExtent().width / (float) instance->GetSwapChain().GetExtent().height, 0.1f, 10.0f);
+ uniformBufferObject.projection[1][1] *= -1;
+
+ uniformBuffer->Update(&uniformBufferObject, instance->GetSwapChain().GetFlightIndex());
+ }
+
VkShaderModule InitializeShaderModule(const std::vector& code)
{
VkShaderModuleCreateInfo createInfo{};
@@ -648,283 +448,22 @@ private:
createInfo.pCode = reinterpret_cast(code.data());
VkShaderModule shaderModule;
- VK_ASSERT(vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
+ VK_ASSERT(vkCreateShaderModule(instance->GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
return shaderModule;
}
-
- QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device)
- {
- QueueFamilyIndices indices;
-
- uint32_t queueFamilyCount = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
- std::vector queueFamilies(queueFamilyCount);
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
-
- int i = 0;
- for (auto&& queueFamily : queueFamilies)
- {
- if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
- {
- indices.graphicsFamily = i;
- }
- VkBool32 presentSupport = false;
- vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
- if (presentSupport)
- {
- indices.presentFamily = i;
- }
- i++;
- }
-
- return indices;
- }
-
- SwapChainSupportDetails FindSwapChainSupport(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;
- }
-
- bool CheckLayerSupport(const std::vector& layers)
- {
- uint32_t layerCount;
- vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
-
- std::vector availableLayers(layerCount);
- vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
-
- std::cout << "Supported Layers: " << std::endl;
- for (auto&& availableLayer : availableLayers)
- {
- std::cout << "\t" << availableLayer.layerName << std::endl;
- }
-
- for (auto&& layer : layers)
- {
- bool layerFound = false;
- for (auto&& availableLayer : availableLayers)
- {
- if (std::strcmp(layer, availableLayer.layerName) == 0)
- {
- layerFound = true;
- break;
- }
- }
- if (!layerFound)
- return false;
- }
- return true;
- }
-
- bool IsPhysicalDeviceSuitable(VkPhysicalDevice device)
- {
- VkPhysicalDeviceProperties deviceProperties;
- vkGetPhysicalDeviceProperties(device, &deviceProperties);
- if (deviceProperties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
- return false;
-
- VkPhysicalDeviceFeatures deviceFeatures;
- vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
- if (!deviceFeatures.fillModeNonSolid)
- return false;
-
- if (!FindQueueFamilies(device).AllRequiredFamiliesSupported())
- return false;
-
- if (!CheckDeviceExtensionSupport(device))
- return false;
-
- if (!FindSwapChainSupport(device).Valid())
- return false;
-
- return true;
- }
-
- std::vector GetRequiredExtensions()
- {
- uint32_t glfwExtensionCount;
- const char** glfwExtensions;
- glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
-
- std::vector extensions{glfwExtensions, glfwExtensions + glfwExtensionCount};
-
- debugMessenger->AddRequiredExtensions(&extensions);
-
- return extensions;
- }
-
- bool CheckDeviceExtensionSupport(VkPhysicalDevice device)
- {
- uint32_t extensionCount;
- vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
- std::vector extensions{extensionCount};
- vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data());
-
- for (auto&& requiredExtension : GetRequiredDeviceExtensions())
- {
- bool found = false;
- for (auto&& extension : extensions)
- {
- if (std::strcmp(requiredExtension, extension.extensionName) == 0)
- {
- found = true;
- break;
- }
- }
- if (!found)
- return false;
- }
- return true;
- }
-
- VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector& availableFormats)
- {
- for (auto&& availableFormat : availableFormats)
- {
- if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
- {
- return availableFormat;
- }
- }
- return availableFormats[0];
- }
-
- VkPresentModeKHR SelectSwapPresentMode(const std::vector& availablePresentModes)
- {
- for (auto&& availablePresentMode : availablePresentModes)
- {
- if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
- {
- return availablePresentMode;
- }
- }
-
- // VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
- return VK_PRESENT_MODE_FIFO_KHR;
- }
-
- VkExtent2D SelectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
- {
- if (capabilities.currentExtent.width != std::numeric_limits::max())
- return capabilities.currentExtent;
-
- int width, height;
- glfwGetFramebufferSize(window, &width, &height);
-
- VkExtent2D extent{width, height};
- extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
- extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
- return extent;
- }
-
- void RecreateSwapChain()
- {
- int width = 0;
- int height = 0;
- glfwGetFramebufferSize(window, &width, &height);
- while (width == 0 || height == 0)
- {
- glfwGetFramebufferSize(window, &width, &height);
- glfwWaitEvents();
- }
-
- vkDeviceWaitIdle(device);
-
- DestroySwapChain();
-
- InitializeSwapChain();
- InitializeSwapChainImageViews();
- InitializeSwapChainFramebuffers();
- }
-
- void DestroySwapChain()
- {
-
- for (auto&& framebuffer : swapChainFramebuffers)
- {
- vkDestroyFramebuffer(device, framebuffer, nullptr);
- }
- for (auto&& swapChainImageView : swapChainImageViews)
- {
- vkDestroyImageView(device, swapChainImageView, nullptr);
- }
- vkDestroySwapchainKHR(device, swapChain, nullptr);
- }
-
- void DestroyVulkan()
- {
- vkDeviceWaitIdle(device);
- for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
- {
- vkDestroyFence(device, inFlightFences[i], nullptr);
- vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
- vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
- }
- vkDestroyCommandPool(device, commandPool, nullptr);
- vkDestroyPipeline(device, graphicsPipeline, nullptr);
- vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
- vkDestroyRenderPass(device, renderPass, nullptr);
- DestroySwapChain();
- vkDestroyDevice(device, nullptr);
- vkDestroySurfaceKHR(instance, surface, nullptr);
- delete debugMessenger;
- vkDestroyInstance(instance, nullptr);
- }
-
- void DestroyWindow()
- {
- glfwDestroyWindow(window);
- }
-
- std::vector GetRequiredDeviceExtensions()
- {
- return {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
- }
-
- static void FramebufferResizeCallback(GLFWwindow* window, int width, int height)
- {
- Application* application = static_cast(glfwGetWindowUserPointer(window));
- application->framebufferResized = true;
- }
};
int main()
{
glfwInit();
- try
{
Application application;
while (application.Update())
{
glfwPollEvents();
}
- }
- catch(std::exception& e)
- {
- std::cerr << "Exception: " << e.what() << std::endl;
- return 1;
}
glfwTerminate();