Triangle posting
https://vulkan-tutorial.com/Vertex_buffers/Staging_buffer Reached the above part of the tutorial. Adding IMGUI now before continuing.
This commit is contained in:
5
.clangd
5
.clangd
@@ -1,5 +1,6 @@
|
||||
CompileFlags:
|
||||
Add:
|
||||
Add:
|
||||
- -I./include
|
||||
- -I/usr/include/vulkan
|
||||
- -I./src
|
||||
- -I./src/public
|
||||
- -std=c++20
|
||||
|
||||
@@ -140,11 +140,11 @@
|
||||
<ClCompile Include="GlfwWindowManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="VulkanGraphicsPipeline.h" />
|
||||
<ClInclude Include="VulkanPipeline.h" />
|
||||
<ClInclude Include="Utilities\FileReader.h" />
|
||||
<ClInclude Include="VulkanContext.h" />
|
||||
<ClInclude Include="VulkanDebugManager.h" />
|
||||
<ClInclude Include="Logger.h" />
|
||||
<ClInclude Include="utlities/Logger.h" />
|
||||
<ClInclude Include="VulkanDeviceManager.h" />
|
||||
<ClInclude Include="VulkanInstanceManager.h" />
|
||||
<ClInclude Include="GlfwWindowManager.h" />
|
||||
@@ -157,4 +157,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
@@ -41,7 +41,7 @@
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Logger.h">
|
||||
<ClInclude Include="utlities/Logger.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GlfwWindowManager.h">
|
||||
@@ -59,7 +59,7 @@
|
||||
<ClInclude Include="VulkanContext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VulkanGraphicsPipeline.h">
|
||||
<ClInclude Include="VulkanPipeline.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Utilities\FileReader.h">
|
||||
@@ -75,4 +75,4 @@
|
||||
<Filter>Shaders</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
BIN
LearningVulkan
Executable file
BIN
LearningVulkan
Executable file
Binary file not shown.
24
Makefile
24
Makefile
@@ -1,13 +1,27 @@
|
||||
CXX = g++
|
||||
|
||||
CFLAGS = -std=c++20 -O2 -Wall -Wextra -I./include
|
||||
CXXFLAGS = -std=c++20 -O2 -Wall -Wextra -I./include -I./src -I./src/private -I./src/public
|
||||
|
||||
LDFLAGS = -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi
|
||||
|
||||
TARGET := LearningVulkan
|
||||
BUILDDIR = build
|
||||
OBJDIR = $(BUILDDIR)/obj
|
||||
|
||||
$(TARGET): ./src/main.cpp
|
||||
$(CXX) $(CFLAGS) -o $(TARGET) ./src/main.cpp $(LDFLAGS)
|
||||
SOURCES = $(shell find ./src -name "*.cpp")
|
||||
|
||||
OBJECTS = $(SOURCES:./src/%.cpp=$(OBJDIR)/%.o)
|
||||
|
||||
TARGET = LearningVulkan
|
||||
|
||||
$(OBJDIR):
|
||||
@mkdir -p $@
|
||||
|
||||
$(OBJDIR)/%.o: ./src/%.cpp | $(OBJDIR)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
|
||||
|
||||
.PHONY: test clean
|
||||
|
||||
@@ -15,4 +29,4 @@ test: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
3
Shaders/compile.sh
Executable file
3
Shaders/compile.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
glslc ./shader.vert -o vert.spv
|
||||
glslc ./shader.frag -o frag.spv
|
||||
@@ -1,20 +1,12 @@
|
||||
#version 450
|
||||
|
||||
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 = vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
}
|
||||
|
||||
|
||||
BIN
Shaders/vert.spv
BIN
Shaders/vert.spv
Binary file not shown.
@@ -1 +0,0 @@
|
||||
#include "VulkanContext.h"
|
||||
@@ -1,52 +0,0 @@
|
||||
#pragma once
|
||||
// #include <vector>
|
||||
// #include <memory>
|
||||
//
|
||||
#include "VulkanInstanceManager.h"
|
||||
#include "VulkanDebugManager.h"
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
const std::vector<const char*> ValidationLayers = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
|
||||
struct FVulkanConfig
|
||||
{
|
||||
bool bValidationEnabled = true;
|
||||
bool bVerboseLogging = false;
|
||||
};
|
||||
|
||||
class VulkanContext
|
||||
{
|
||||
public:
|
||||
VulkanContext();
|
||||
~VulkanContext();
|
||||
|
||||
void Initialize(FVulkanConfig& Config);
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
FVulkanConfig Config = {};
|
||||
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice Device = VK_NULL_HANDLE;
|
||||
VkQueue GraphicsQueue = VK_NULL_HANDLE;
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE;
|
||||
|
||||
public:
|
||||
static VulkanDebugManager DebugManager;
|
||||
|
||||
private:
|
||||
VulkanInstanceManager InstanceManager;
|
||||
|
||||
public:
|
||||
VkInstance GetInstance() const { return Instance; }
|
||||
VkPhysicalDevice GetPhysicalDevice() const { return PhysicalDevice; }
|
||||
VkDevice GetDevice() const { return Device; }
|
||||
VkQueue GetGraphicsQueue() const { return GraphicsQueue; }
|
||||
VkSurfaceKHR GetSurface() const { return Surface; }
|
||||
};
|
||||
@@ -1,442 +0,0 @@
|
||||
#include "VulkanDeviceManager.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint> // Necessary for uint32_t
|
||||
#include <limits> // Necessary for std::numeric_limits
|
||||
#include <algorithm> // Necessary for std::clamp
|
||||
|
||||
#include "Logger.h"
|
||||
#include "GlfwWindowManager.h"
|
||||
#include <set>
|
||||
|
||||
std::vector<VkImage> VulkanDeviceManager::SwapChainImages = {};
|
||||
|
||||
VulkanDeviceManager::VulkanDeviceManager()
|
||||
{
|
||||
}
|
||||
|
||||
VulkanDeviceManager::~VulkanDeviceManager()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
VulkanDeviceManager::VulkanDeviceManager(VulkanDeviceManager&& Other) noexcept
|
||||
: PhysicalDevice(std::exchange(Other.PhysicalDevice, VK_NULL_HANDLE))
|
||||
, Instance(std::exchange(Other.Instance, VK_NULL_HANDLE))
|
||||
, Device(std::exchange(Other.Device, VK_NULL_HANDLE))
|
||||
, GraphicsQueue(std::exchange(Other.GraphicsQueue, VK_NULL_HANDLE))
|
||||
, bEnableValidationLayers(std::exchange(Other.bEnableValidationLayers, false))
|
||||
, ValidationLayers(std::move(Other.ValidationLayers))
|
||||
{
|
||||
}
|
||||
|
||||
VulkanDeviceManager& VulkanDeviceManager::operator=(VulkanDeviceManager&& Other) noexcept
|
||||
{
|
||||
if (this != &Other)
|
||||
{
|
||||
Cleanup(); // Clean up current resources
|
||||
|
||||
// Transfer resources from Other
|
||||
PhysicalDevice = std::exchange(Other.PhysicalDevice, VK_NULL_HANDLE);
|
||||
Instance = std::exchange(Other.Instance, VK_NULL_HANDLE);
|
||||
Device = std::exchange(Other.Device, VK_NULL_HANDLE);
|
||||
GraphicsQueue = std::exchange(Other.GraphicsQueue, VK_NULL_HANDLE);
|
||||
bEnableValidationLayers = std::exchange(Other.bEnableValidationLayers, false);
|
||||
ValidationLayers = std::move(Other.ValidationLayers);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::Initialize(
|
||||
VkInstance Instance,
|
||||
bool bEnableValidationLayers,
|
||||
const std::vector<const char*>& ValidationLayers)
|
||||
{
|
||||
if (IsInitialized())
|
||||
{
|
||||
Log::Warning("Already Initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
this->Instance = Instance;
|
||||
this->bEnableValidationLayers = bEnableValidationLayers;
|
||||
this->ValidationLayers = &ValidationLayers;
|
||||
|
||||
PickPhysicalDevice();
|
||||
CreateLogicalDevice();
|
||||
CreateSwapChain();
|
||||
CreateImageViews();
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::Cleanup()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
Log::Warning("Not Initialized.");
|
||||
return;
|
||||
}
|
||||
for (auto ImageView : SwapChainImageViews)
|
||||
{
|
||||
vkDestroyImageView(Device, ImageView, nullptr);
|
||||
}
|
||||
vkDestroySwapchainKHR(Device, SwapChain, nullptr);
|
||||
|
||||
vkDestroySurfaceKHR(Instance, GlfwWindowManager::Surface, nullptr);
|
||||
vkDestroyDevice(Device, nullptr);
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::PickPhysicalDevice()
|
||||
{
|
||||
uint32_t DeviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(Instance, &DeviceCount, nullptr);
|
||||
|
||||
if (DeviceCount == 0)
|
||||
{
|
||||
Log::Error("Failed to find GPU with Vulkan Support.");
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> Devices(DeviceCount);
|
||||
vkEnumeratePhysicalDevices(Instance, &DeviceCount, Devices.data());
|
||||
|
||||
std::multimap<int, VkPhysicalDevice> Candidates;
|
||||
|
||||
for (const auto& Device : Devices)
|
||||
{
|
||||
if (IsDeviceSuitable(Device))
|
||||
{
|
||||
int Score = RateDeviceSuitability(Device);
|
||||
Candidates.insert(std::make_pair(Score, Device));
|
||||
}
|
||||
}
|
||||
|
||||
if (Candidates.rbegin()->first > 0)
|
||||
{
|
||||
PhysicalDevice = Candidates.rbegin()->second;
|
||||
Log::Info("Suitable GPU found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Error("Failed to find a suitable GPU.");
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanDeviceManager::IsDeviceSuitable(VkPhysicalDevice Device)
|
||||
{
|
||||
QueueFamilyIndices Indices = FindQueueFamilies(Device);
|
||||
|
||||
bool bExtensionsSupported = CheckDeviceExtensionSupport(Device);
|
||||
|
||||
bool bSwapChainAdequate = false;
|
||||
if (bExtensionsSupported)
|
||||
{
|
||||
SwapChainSupportDetails SwapChainSupport = QuerySwapChainSupport(Device);
|
||||
bSwapChainAdequate = !SwapChainSupport.Formats.empty() && !SwapChainSupport.PresentModes.empty();
|
||||
}
|
||||
|
||||
return Indices.IsComplete() && bExtensionsSupported && bSwapChainAdequate;
|
||||
}
|
||||
|
||||
int VulkanDeviceManager::RateDeviceSuitability(VkPhysicalDevice Device)
|
||||
{
|
||||
VkPhysicalDeviceProperties DeviceProperties;
|
||||
vkGetPhysicalDeviceProperties(Device, &DeviceProperties);
|
||||
|
||||
VkPhysicalDeviceFeatures DeviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(Device, &DeviceFeatures);
|
||||
|
||||
int Score = 0;
|
||||
|
||||
if (DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
{
|
||||
Score += 100;
|
||||
}
|
||||
|
||||
Score += DeviceProperties.limits.maxImageDimension2D;
|
||||
|
||||
if (!DeviceFeatures.geometryShader)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Score;
|
||||
}
|
||||
|
||||
bool VulkanDeviceManager::CheckDeviceExtensionSupport(VkPhysicalDevice Device)
|
||||
{
|
||||
uint32_t ExtensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> AvailableExtensions(ExtensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data());
|
||||
|
||||
std::set<std::string> RequiredExtensions(DeviceExtensions.begin(), DeviceExtensions.end());
|
||||
|
||||
for (const auto& Extension : AvailableExtensions)
|
||||
{
|
||||
RequiredExtensions.erase(Extension.extensionName);
|
||||
}
|
||||
|
||||
return RequiredExtensions.empty();
|
||||
}
|
||||
|
||||
QueueFamilyIndices VulkanDeviceManager::FindQueueFamilies(VkPhysicalDevice Device)
|
||||
{
|
||||
QueueFamilyIndices Indices;
|
||||
|
||||
uint32_t QueueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> QueueFamilies(QueueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilies.data());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& QueueFamily : QueueFamilies)
|
||||
{
|
||||
if (QueueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
Indices.GraphicsFamily = i;
|
||||
}
|
||||
|
||||
VkBool32 PresentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(Device, i, GlfwWindowManager::Surface, &PresentSupport);
|
||||
|
||||
if (PresentSupport)
|
||||
{
|
||||
Indices.PresentFamily = i;
|
||||
}
|
||||
if (Indices.IsComplete())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return Indices;
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::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 = Indices.GraphicsFamily.value();
|
||||
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 (bEnableValidationLayers)
|
||||
{
|
||||
CreateInfo.enabledLayerCount = static_cast<uint32_t>(ValidationLayers->size());
|
||||
CreateInfo.ppEnabledLayerNames = ValidationLayers->data();
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInfo.enabledLayerCount = 0;
|
||||
}
|
||||
|
||||
if (vkCreateDevice(PhysicalDevice, &CreateInfo, nullptr, &Device) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create logical device!");
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(Device, Indices.GraphicsFamily.value(), 0, &GraphicsQueue);
|
||||
vkGetDeviceQueue(Device, Indices.PresentFamily.value(), 0, &PresentQueue);
|
||||
}
|
||||
|
||||
SwapChainSupportDetails VulkanDeviceManager::QuerySwapChainSupport(VkPhysicalDevice Device)
|
||||
{
|
||||
SwapChainSupportDetails Details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device, GlfwWindowManager::Surface, &Details.Capabilities);
|
||||
|
||||
uint32_t FormatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(Device, GlfwWindowManager::Surface, &FormatCount, nullptr);
|
||||
|
||||
if (FormatCount != 0)
|
||||
{
|
||||
Details.Formats.resize(FormatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(Device, GlfwWindowManager::Surface, &FormatCount, Details.Formats.data());
|
||||
}
|
||||
|
||||
uint32_t PresentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(Device, GlfwWindowManager::Surface, &PresentModeCount, nullptr);
|
||||
|
||||
if (PresentModeCount != 0)
|
||||
{
|
||||
Details.PresentModes.resize(PresentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(Device, GlfwWindowManager::Surface, &PresentModeCount, Details.PresentModes.data());
|
||||
}
|
||||
|
||||
return Details;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR VulkanDeviceManager::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats)
|
||||
{
|
||||
for (const auto& AvailableFormat : AvailableFormats)
|
||||
{
|
||||
if (AvailableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && AvailableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
{
|
||||
return AvailableFormat;
|
||||
}
|
||||
}
|
||||
return AvailableFormats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR VulkanDeviceManager::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes)
|
||||
{
|
||||
for (const auto& AvailablePresentMode : AvailablePresentModes)
|
||||
{
|
||||
if (AvailablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
{
|
||||
return AvailablePresentMode;
|
||||
}
|
||||
}
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkExtent2D VulkanDeviceManager::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities)
|
||||
{
|
||||
if (Capabilities.currentExtent.width != (std::numeric_limits<uint32_t>::max)())
|
||||
{
|
||||
return Capabilities.currentExtent;
|
||||
}
|
||||
else
|
||||
{
|
||||
int Width, Height;
|
||||
glfwGetFramebufferSize(GlfwWindowManager::Window, &Width, &Height);
|
||||
|
||||
VkExtent2D ActualExtent = {
|
||||
static_cast<uint32_t>(Width),
|
||||
static_cast<uint32_t>(Height)
|
||||
};
|
||||
|
||||
ActualExtent.width = std::clamp(ActualExtent.width, Capabilities.minImageExtent.width, Capabilities.maxImageExtent.width);
|
||||
ActualExtent.height = std::clamp(ActualExtent.height, Capabilities.minImageExtent.height, Capabilities.maxImageExtent.height);
|
||||
|
||||
return ActualExtent;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::CreateSwapChain()
|
||||
{
|
||||
SwapChainSupportDetails SwapChainSupport = QuerySwapChainSupport(PhysicalDevice);
|
||||
|
||||
VkSurfaceFormatKHR SurfaceFormat = ChooseSwapSurfaceFormat(SwapChainSupport.Formats);
|
||||
VkPresentModeKHR PresentMode = ChooseSwapPresentMode(SwapChainSupport.PresentModes);
|
||||
VkExtent2D Extent = ChooseSwapExtent(SwapChainSupport.Capabilities);
|
||||
|
||||
uint32_t ImageCount = SwapChainSupport.Capabilities.minImageCount + 1;
|
||||
|
||||
if (SwapChainSupport.Capabilities.maxImageCount > 0 && ImageCount > SwapChainSupport.Capabilities.maxImageCount)
|
||||
{
|
||||
ImageCount = SwapChainSupport.Capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR CreateInfo{};
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
CreateInfo.surface = GlfwWindowManager::Surface;
|
||||
|
||||
CreateInfo.minImageCount = ImageCount;
|
||||
CreateInfo.imageFormat = SurfaceFormat.format;
|
||||
CreateInfo.imageColorSpace = SurfaceFormat.colorSpace;
|
||||
CreateInfo.imageExtent = Extent;
|
||||
CreateInfo.imageArrayLayers = 1;
|
||||
CreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // may need VK_IMAGE_USAGE_TRANSFER_DST_BIT for post processing https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain#:~:text=VK%5FIMAGE%5FUSAGE%5FTRANSFER%5FDST%5FBIT
|
||||
|
||||
QueueFamilyIndices Indices = FindQueueFamilies(PhysicalDevice);
|
||||
uint32_t QueueFamilyIndices[] = { Indices.GraphicsFamily.value(),
|
||||
Indices.PresentFamily.value() };
|
||||
|
||||
if (Indices.GraphicsFamily != Indices.PresentFamily)
|
||||
{
|
||||
CreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
CreateInfo.queueFamilyIndexCount = 2;
|
||||
CreateInfo.pQueueFamilyIndices = QueueFamilyIndices;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
CreateInfo.queueFamilyIndexCount = 0;
|
||||
CreateInfo.pQueueFamilyIndices = nullptr;
|
||||
}
|
||||
|
||||
CreateInfo.preTransform = SwapChainSupport.Capabilities.currentTransform;
|
||||
CreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
CreateInfo.presentMode = PresentMode;
|
||||
CreateInfo.clipped = VK_TRUE;
|
||||
CreateInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
if (vkCreateSwapchainKHR(Device, &CreateInfo, nullptr, &SwapChain) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create swap chain.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created swap chain.");
|
||||
}
|
||||
|
||||
vkGetSwapchainImagesKHR(Device, SwapChain, &ImageCount, nullptr);
|
||||
SwapChainImages.resize(ImageCount);
|
||||
vkGetSwapchainImagesKHR(Device, SwapChain, &ImageCount, SwapChainImages.data());
|
||||
|
||||
SwapChainImageFormat = SurfaceFormat.format;
|
||||
SwapChainExtent = Extent;
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::CreateImageViews()
|
||||
{
|
||||
SwapChainImageViews.resize(SwapChainImages.size());
|
||||
|
||||
int CreatedViews = 0;
|
||||
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;
|
||||
|
||||
if (vkCreateImageView(Device, &CreateInfo, nullptr, &SwapChainImageViews[i]) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create image views.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatedViews++;
|
||||
}
|
||||
}
|
||||
|
||||
Log::Info("Successfully created " + std::to_string(CreatedViews) + " image views.");
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
const std::vector<const char*> DeviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
std::optional<uint32_t> GraphicsFamily;
|
||||
std::optional<uint32_t> PresentFamily;
|
||||
|
||||
bool IsComplete()
|
||||
{
|
||||
return GraphicsFamily.has_value() && PresentFamily.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct SwapChainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR Capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> Formats;
|
||||
std::vector<VkPresentModeKHR> PresentModes;
|
||||
};
|
||||
|
||||
class VulkanDeviceManager
|
||||
{
|
||||
public:
|
||||
VulkanDeviceManager();
|
||||
~VulkanDeviceManager();
|
||||
|
||||
VulkanDeviceManager(const VulkanDeviceManager&) = delete;
|
||||
VulkanDeviceManager& operator=(const VulkanDeviceManager&) = delete;
|
||||
|
||||
VulkanDeviceManager(VulkanDeviceManager&& Other) noexcept;
|
||||
VulkanDeviceManager& operator=(VulkanDeviceManager&& Other) noexcept;
|
||||
|
||||
void Initialize(
|
||||
VkInstance Instance,
|
||||
bool EnableValidationLayers,
|
||||
const std::vector<const char*>& ValidationLayers);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
bool bInitialized = PhysicalDevice && Device && Instance && GraphicsQueue;
|
||||
return bInitialized;
|
||||
}
|
||||
|
||||
static std::vector<VkImage> SwapChainImages;
|
||||
|
||||
private:
|
||||
VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE;
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
VkDevice Device = VK_NULL_HANDLE;
|
||||
VkQueue GraphicsQueue = VK_NULL_HANDLE;
|
||||
VkQueue PresentQueue = VK_NULL_HANDLE;
|
||||
|
||||
VkSwapchainKHR SwapChain = VK_NULL_HANDLE;
|
||||
VkFormat SwapChainImageFormat;
|
||||
VkExtent2D SwapChainExtent;
|
||||
|
||||
std::vector<VkImageView> SwapChainImageViews;
|
||||
|
||||
bool bEnableValidationLayers = false;
|
||||
|
||||
const std::vector<const char*>* ValidationLayers = nullptr;
|
||||
|
||||
void PickPhysicalDevice();
|
||||
|
||||
bool IsDeviceSuitable(VkPhysicalDevice Device);
|
||||
|
||||
int RateDeviceSuitability(VkPhysicalDevice Device);
|
||||
|
||||
bool CheckDeviceExtensionSupport(VkPhysicalDevice Device);
|
||||
|
||||
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice Device);
|
||||
|
||||
void CreateLogicalDevice();
|
||||
|
||||
SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device);
|
||||
|
||||
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats);
|
||||
|
||||
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes);
|
||||
|
||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities);
|
||||
|
||||
void CreateSwapChain();
|
||||
|
||||
void CreateImageViews();
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "FileReader.h"
|
||||
#include "vulkan_core.h"
|
||||
|
||||
class VulkanGraphicsPipeline
|
||||
{
|
||||
public:
|
||||
void CreateGraphicsPipeline()
|
||||
{
|
||||
auto VertShaderCode = ReadFile("Shaders/vert.spv");
|
||||
auto FragShaderCode = ReadFile("Shaders/frag.spv");
|
||||
|
||||
Log::Info("Vert buffer size: " + std::to_string(VertShaderCode.size()));
|
||||
Log::Info("Frag buffer size: " + std::to_string(FragShaderCode.size()));
|
||||
}
|
||||
|
||||
VkShaderModule CreateShaderModule(const std::vector<char>& Code)
|
||||
{
|
||||
VkShaderModuleCreateInfo CreateInfo{};
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
CreateInfo.codeSize = Code.size();
|
||||
CreateInfo.pCode = reinterpret_cast<const uint32_t*>(Code.data());
|
||||
|
||||
VkShaderModule ShaderModule;
|
||||
// if (vkCreateShaderModule(Device))
|
||||
return ShaderModule;
|
||||
}
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "VulkanDebugManager.h"
|
||||
#include "VulkanDeviceManager.h"
|
||||
#include "GlfwWindowManager.h"
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
const std::vector<const char*> ValidationLayers = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
|
||||
struct FVulkanConfig
|
||||
{
|
||||
bool bValidationEnabled = true;
|
||||
bool bVerboseLogging = false;
|
||||
};
|
||||
|
||||
class VulkanInstanceManager
|
||||
{
|
||||
public:
|
||||
VulkanInstanceManager();
|
||||
~VulkanInstanceManager();
|
||||
|
||||
VulkanInstanceManager(const VulkanInstanceManager&) = delete;
|
||||
VulkanInstanceManager& operator=(const VulkanInstanceManager&) = delete;
|
||||
|
||||
VulkanInstanceManager(VulkanInstanceManager&& Other) noexcept;
|
||||
VulkanInstanceManager& operator=(VulkanInstanceManager&& Other) noexcept;
|
||||
|
||||
// void Initialize(const FVulkanConfig& Config);
|
||||
void Initialize(bool bEnableValidationLayers);
|
||||
void SetupDebug();
|
||||
void SetupDevice();
|
||||
|
||||
// void Initialize(VulkanDebugManager& inDebugManager, bool inValidationEnabled);
|
||||
void Cleanup();
|
||||
|
||||
bool IsInitialized() const { return Instance != VK_NULL_HANDLE; }
|
||||
|
||||
const std::vector<const char*>& GetValidationLayers() const
|
||||
{
|
||||
return ValidationLayers;
|
||||
}
|
||||
|
||||
const VkInstance GetInstance() const { return Instance; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<VulkanDebugManager> VkDebugManager = nullptr;
|
||||
std::unique_ptr<VulkanDeviceManager> VkDeviceManager = nullptr;
|
||||
|
||||
bool bValidationEnabled = false;
|
||||
bool bVerboseLogging = false;
|
||||
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<const char*> GetRequiredExtensions();
|
||||
|
||||
bool CheckValidationLayerSupport();
|
||||
|
||||
void CreateInstance();
|
||||
};
|
||||
58
src/main.cpp
Normal file → Executable file
58
src/main.cpp
Normal file → Executable file
@@ -1,27 +1,27 @@
|
||||
|
||||
#include "Logger.h"
|
||||
#include "VulkanInstanceManager.h"
|
||||
#include "VulkanDeviceManager.h"
|
||||
#include "VulkanDebugManager.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "utilities/Logger.h"
|
||||
#include "GlfwWindowManager.h"
|
||||
#include "VulkanGraphicsPipeline.h"
|
||||
// #include "VulkanContext.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
struct AppConfig
|
||||
{
|
||||
std::string Title = "Learning Vulkan";
|
||||
uint32_t Width = 800;
|
||||
uint32_t Height = 600;
|
||||
bool bResizable = false;
|
||||
bool bResizable = true;
|
||||
bool bFullscreen = false;
|
||||
bool bValidationEnabled = true;
|
||||
bool bValidationEnabled = false;
|
||||
bool bVerboseLogging = false;
|
||||
};
|
||||
|
||||
void test () {
|
||||
if (true) return;
|
||||
|
||||
}
|
||||
const std::vector<Vertex> TriangleVertices = {
|
||||
{ { 0.0f, -0.5f }, { 1.0f, 1.0f, 1.0f } },
|
||||
{ { 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f } },
|
||||
{ { -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f } }
|
||||
};
|
||||
|
||||
class HelloTriangleApplication
|
||||
{
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
void Run()
|
||||
{
|
||||
Initialization();
|
||||
Log::Info("Initialization finished...");
|
||||
MainLoop();
|
||||
Cleanup();
|
||||
}
|
||||
@@ -36,25 +37,24 @@ public:
|
||||
private:
|
||||
AppConfig Settings = {};
|
||||
|
||||
VulkanInstanceManager InstanceManager;
|
||||
GlfwWindowManager WindowManager;
|
||||
GlfwWindowManager WindowManager;
|
||||
VulkanContext VkContext;
|
||||
|
||||
void Initialization()
|
||||
{
|
||||
InitGlfw();
|
||||
InitVulkan();
|
||||
InstanceManager.SetupDebug();
|
||||
WindowManager.CreateSurface(InstanceManager.GetInstance());
|
||||
InstanceManager.SetupDevice();
|
||||
}
|
||||
|
||||
void InitVulkan()
|
||||
{
|
||||
FVulkanConfig Config = {
|
||||
Settings.bValidationEnabled,
|
||||
Settings.bVerboseLogging
|
||||
Settings.bVerboseLogging,
|
||||
WindowManager.GetWindow(),
|
||||
TriangleVertices
|
||||
};
|
||||
InstanceManager.Initialize(Config);
|
||||
VkContext.Initialize(Config);
|
||||
}
|
||||
|
||||
void InitGlfw()
|
||||
@@ -67,6 +67,20 @@ private:
|
||||
Settings.bFullscreen
|
||||
};
|
||||
WindowManager.Initialize(Config);
|
||||
|
||||
glfwSetWindowUserPointer(WindowManager.GetWindow(), this);
|
||||
glfwSetFramebufferSizeCallback(WindowManager.GetWindow(), FramebufferResizeCallback);
|
||||
}
|
||||
|
||||
static void FramebufferResizeCallback(GLFWwindow* Window, int Width, int Height)
|
||||
{
|
||||
auto App = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(Window));
|
||||
App->VkContext.SetFramebufferResized(true);
|
||||
}
|
||||
|
||||
void DrawFrame()
|
||||
{
|
||||
VkContext.DrawFrame();
|
||||
}
|
||||
|
||||
void MainLoop()
|
||||
@@ -74,13 +88,15 @@ private:
|
||||
while (!WindowManager.ShouldClose())
|
||||
{
|
||||
WindowManager.PollEvents();
|
||||
DrawFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
WindowManager.Cleanup(InstanceManager.GetInstance());
|
||||
InstanceManager.Cleanup();
|
||||
Log::Info("Cleaning up...");
|
||||
VkContext.Cleanup();
|
||||
WindowManager.Cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
93
src/GlfwWindowManager.cpp → src/private/GlfwWindowManager.cpp
Normal file → Executable file
93
src/GlfwWindowManager.cpp → src/private/GlfwWindowManager.cpp
Normal file → Executable file
@@ -1,41 +1,15 @@
|
||||
#include "GlfwWindowManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
VkSurfaceKHR GlfwWindowManager::Surface = VK_NULL_HANDLE;
|
||||
GLFWwindow* GlfwWindowManager::Window = nullptr;
|
||||
|
||||
GlfwWindowManager::GlfwWindowManager() = default;
|
||||
GlfwWindowManager::GlfwWindowManager()
|
||||
{
|
||||
}
|
||||
|
||||
GlfwWindowManager::~GlfwWindowManager()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
// GlfwWindowManager::GlfwWindowManager(GlfwWindowManager&& Other) noexcept
|
||||
// : Window(Other.Window), Config(Other.Config), Surface(Other.Surface)
|
||||
//{
|
||||
// Other.Window = nullptr;
|
||||
// }
|
||||
//
|
||||
// GlfwWindowManager& GlfwWindowManager::operator=(GlfwWindowManager&& Other) noexcept
|
||||
//{
|
||||
// if (this != &Other)
|
||||
// {
|
||||
// Cleanup();
|
||||
//
|
||||
// Window = Other.Window;
|
||||
// Config = Other.Config;
|
||||
// Surface = Other.Surface;
|
||||
//
|
||||
// Other.Window = nullptr;
|
||||
// }
|
||||
//
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
void GlfwWindowManager::Initialize(const FWindowConfig& Config)
|
||||
{
|
||||
if (IsInitialized())
|
||||
@@ -48,7 +22,7 @@ void GlfwWindowManager::Initialize(const FWindowConfig& Config)
|
||||
InitializeGlfw();
|
||||
}
|
||||
|
||||
void GlfwWindowManager::Cleanup(VkInstance Instance)
|
||||
void GlfwWindowManager::Cleanup()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
@@ -92,46 +66,6 @@ void GlfwWindowManager::SetTitle(const std::string& Title)
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::CreateSurface(VkInstance Instance)
|
||||
{
|
||||
if (!Window)
|
||||
{
|
||||
Log::Error("Window not initialized.");
|
||||
}
|
||||
|
||||
if (!Instance)
|
||||
{
|
||||
Log::Error("Instance is null.");
|
||||
}
|
||||
|
||||
VkResult result = glfwCreateWindowSurface(Instance, Window, nullptr, &Surface);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
std::string errorMsg;
|
||||
switch (result)
|
||||
{
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
errorMsg = "VK_ERROR_EXTENSION_NOT_PRESENT - Required extension not present";
|
||||
break;
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
errorMsg = "VK_ERROR_INITIALIZATION_FAILED - Initialization failed";
|
||||
break;
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||
errorMsg = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR - Native window already in use";
|
||||
break;
|
||||
default:
|
||||
errorMsg = "Unknown error code: " + std::to_string(result);
|
||||
break;
|
||||
}
|
||||
|
||||
Log::Error("Failed to create window surface: " + errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Window surface created successfully.");
|
||||
}
|
||||
}
|
||||
|
||||
void GlfwWindowManager::SetResizeCallback(GLFWwindowsizefun Callback)
|
||||
{
|
||||
if (Window)
|
||||
@@ -191,8 +125,16 @@ void GlfwWindowManager::InitializeGlfw()
|
||||
}
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, Config.bResizable ? GLFW_TRUE : GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_DECORATED, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
glfwWindowHintString(GLFW_WAYLAND_APP_ID, Config.Title.c_str());
|
||||
|
||||
Window = glfwCreateWindow(
|
||||
Config.Width,
|
||||
@@ -209,4 +151,13 @@ void GlfwWindowManager::InitializeGlfw()
|
||||
{
|
||||
Log::Info("Created GLFW window successfully.");
|
||||
}
|
||||
|
||||
glfwSetWindowSize(Window, Config.Width, Config.Height);
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
if (mode)
|
||||
{
|
||||
int xPos = (mode->width - Config.Width) / 2;
|
||||
int yPos = (mode->height - Config.Height) / 2;
|
||||
glfwSetWindowPos(Window, xPos, yPos);
|
||||
}
|
||||
}
|
||||
125
src/private/VulkanCommandBuffers.cpp
Normal file
125
src/private/VulkanCommandBuffers.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "VulkanCommandBuffers.h"
|
||||
|
||||
#include "utilities/Logger.h"
|
||||
#include <cstdint>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
void VulkanCommandBuffers::Initialize(
|
||||
VkDevice InDevice,
|
||||
VkRenderPass InRenderPass)
|
||||
{
|
||||
Device = InDevice;
|
||||
RenderPass = InRenderPass;
|
||||
}
|
||||
|
||||
void VulkanCommandBuffers::Cleanup()
|
||||
{
|
||||
vkDestroyCommandPool(Device, CommandPool, nullptr);
|
||||
}
|
||||
|
||||
void VulkanCommandBuffers::CreateCommandPool(std::optional<uint32_t> GraphicsFamily)
|
||||
{
|
||||
VkCommandPoolCreateInfo PoolInfo{};
|
||||
PoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
PoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
PoolInfo.queueFamilyIndex = GraphicsFamily.value();
|
||||
|
||||
if (vkCreateCommandPool(Device, &PoolInfo, nullptr, &CommandPool) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create command pool!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created command pool");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanCommandBuffers::CreateCommandBuffers(int FramesInFlight)
|
||||
{
|
||||
CommandBuffers.resize(FramesInFlight);
|
||||
VkCommandBufferAllocateInfo AllocateInfo{};
|
||||
AllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
AllocateInfo.commandPool = CommandPool;
|
||||
AllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
AllocateInfo.commandBufferCount = (uint32_t)CommandBuffers.size();
|
||||
|
||||
if (vkAllocateCommandBuffers(Device, &AllocateInfo, CommandBuffers.data()) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to allocate command buffers!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully allocated command buffers.");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanCommandBuffers::RecordCommandBuffer(
|
||||
VkCommandBuffer InCommandBuffer,
|
||||
uint32_t ImageIndex,
|
||||
VkBuffer InVertexBuffer,
|
||||
std::vector<Vertex> InVertices,
|
||||
VkRenderPass RenderPass,
|
||||
VkExtent2D SwapChainExtent,
|
||||
VkPipeline GraphicsPipeline,
|
||||
std::vector<VkFramebuffer> SwapChainFramebuffers)
|
||||
{
|
||||
VkCommandBufferBeginInfo BeginInfo{};
|
||||
BeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
BeginInfo.flags = 0;
|
||||
BeginInfo.pInheritanceInfo = nullptr;
|
||||
|
||||
if (vkBeginCommandBuffer(InCommandBuffer, &BeginInfo) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to begin recording command buffer!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log::Info("Successfully began recording command buffers.");
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo RenderPassInfo{};
|
||||
RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
RenderPassInfo.renderPass = RenderPass;
|
||||
RenderPassInfo.framebuffer = SwapChainFramebuffers[ImageIndex];
|
||||
RenderPassInfo.renderArea.offset = { 0, 0 };
|
||||
RenderPassInfo.renderArea.extent = { SwapChainExtent };
|
||||
|
||||
VkClearValue ClearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
RenderPassInfo.clearValueCount = 1;
|
||||
RenderPassInfo.pClearValues = &ClearColor;
|
||||
|
||||
vkCmdBeginRenderPass(InCommandBuffer, &RenderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(InCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipeline);
|
||||
|
||||
VkViewport Viewport{};
|
||||
Viewport.x = 0.0f;
|
||||
Viewport.y = 0.0f;
|
||||
Viewport.width = static_cast<float>(SwapChainExtent.width);
|
||||
Viewport.height = static_cast<float>(SwapChainExtent.height);
|
||||
Viewport.minDepth = 0.0f;
|
||||
Viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(InCommandBuffer, 0, 1, &Viewport);
|
||||
|
||||
VkRect2D Scissor{};
|
||||
Scissor.offset = { 0, 0 };
|
||||
Scissor.extent = SwapChainExtent;
|
||||
vkCmdSetScissor(InCommandBuffer, 0, 1, &Scissor);
|
||||
|
||||
VkBuffer VertexBuffers[] = { InVertexBuffer };
|
||||
VkDeviceSize Offsets[] = { 0 };
|
||||
vkCmdBindVertexBuffers(InCommandBuffer, 0, 1, VertexBuffers, Offsets);
|
||||
|
||||
vkCmdDraw(InCommandBuffer, static_cast<uint32_t>(InVertices.size()), 1, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(InCommandBuffer);
|
||||
|
||||
if (vkEndCommandBuffer(InCommandBuffer) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to record command buffer!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log::Info("Successfully recorded command buffer.");
|
||||
}
|
||||
}
|
||||
287
src/private/VulkanContext.cpp
Executable file
287
src/private/VulkanContext.cpp
Executable file
@@ -0,0 +1,287 @@
|
||||
#include "VulkanContext.h"
|
||||
#include "VulkanDeviceManager.h"
|
||||
#include "VulkanFramebuffers.h"
|
||||
#include "VulkanSwapChain.h"
|
||||
#include "VulkanVertexBuffer.h"
|
||||
#include "utilities/Logger.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <cstdint>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
VulkanContext::VulkanContext()
|
||||
{
|
||||
}
|
||||
|
||||
VulkanContext::~VulkanContext()
|
||||
{
|
||||
}
|
||||
|
||||
void VulkanContext::Initialize(FVulkanConfig& InConfig)
|
||||
{
|
||||
Config = InConfig;
|
||||
|
||||
if (Config.bValidationEnabled)
|
||||
{
|
||||
InstanceManager.CreateInstance(&DebugManager);
|
||||
DebugManager.Initialize(InstanceManager.GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
InstanceManager.CreateInstance();
|
||||
}
|
||||
|
||||
CreateSurface(InConfig.Window);
|
||||
|
||||
DeviceManager.Initialize(FDeviceConfig(
|
||||
InstanceManager.GetInstance(),
|
||||
Config.bValidationEnabled,
|
||||
Surface,
|
||||
InConfig.Window));
|
||||
DeviceManager.PickPhysicalDevice();
|
||||
DeviceManager.CreateLogicalDevice();
|
||||
|
||||
SwapChain.Initialize(FSwapConfig(
|
||||
DeviceManager.GetDevice(),
|
||||
Surface,
|
||||
Config.Window,
|
||||
DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily,
|
||||
DeviceManager.GetPhysicalQueueFamilies().PresentFamily,
|
||||
DeviceManager.GetSwapChainSupport().Capabilities,
|
||||
DeviceManager.GetSwapChainSupport().Formats,
|
||||
DeviceManager.GetSwapChainSupport().PresentModes));
|
||||
SwapChain.CreateSwapChain();
|
||||
SwapChain.CreateImageViews();
|
||||
|
||||
RenderPass.Initialize(DeviceManager.GetDevice());
|
||||
RenderPass.CreateRenderPass(SwapChain.GetSwapChainImageFormat());
|
||||
|
||||
GraphicsPipeline.Initialize(DeviceManager.GetDevice());
|
||||
GraphicsPipeline.CreateGraphicsPipeline(SwapChain.GetSwapChainExtent(), RenderPass.GetRenderPass());
|
||||
|
||||
Framebuffers.Initialize(FFramebufferConfig(
|
||||
DeviceManager.GetDevice(),
|
||||
RenderPass.GetRenderPass(),
|
||||
SwapChain.GetSwapChainImageViews(),
|
||||
SwapChain.GetSwapChainExtent()));
|
||||
Framebuffers.CreateFramebuffers();
|
||||
|
||||
CommandBuffers.Initialize(DeviceManager.GetDevice(), RenderPass.GetRenderPass());
|
||||
CommandBuffers.CreateCommandPool(DeviceManager.GetPhysicalQueueFamilies().GraphicsFamily);
|
||||
|
||||
VertexBuffer.Initialize(FVertexBufferConfig(DeviceManager.GetDevice(), DeviceManager.GetPhysicalDevice()));
|
||||
VertexBuffer.CreateVertexBuffer(Config.Vertices);
|
||||
|
||||
CommandBuffers.CreateCommandBuffers(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
CreateSyncObjects();
|
||||
}
|
||||
|
||||
void VulkanContext::Cleanup()
|
||||
{
|
||||
CleanupSwapChain();
|
||||
|
||||
VertexBuffer.Cleanup();
|
||||
|
||||
GraphicsPipeline.Cleanup();
|
||||
RenderPass.Cleanup();
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
vkDestroySemaphore(DeviceManager.GetDevice(), ImageAvailableSemaphores[i], nullptr);
|
||||
vkDestroySemaphore(DeviceManager.GetDevice(), RenderFinishedSemaphores[i], nullptr);
|
||||
vkDestroyFence(DeviceManager.GetDevice(), InFlightFences[i], nullptr);
|
||||
}
|
||||
|
||||
CommandBuffers.Cleanup();
|
||||
|
||||
DeviceManager.Cleanup();
|
||||
|
||||
if (Config.bValidationEnabled)
|
||||
{
|
||||
DebugManager.Cleanup();
|
||||
}
|
||||
|
||||
vkDestroySurfaceKHR(InstanceManager.GetInstance(), Surface, nullptr);
|
||||
InstanceManager.Cleanup();
|
||||
}
|
||||
|
||||
void VulkanContext::CreateSurface(GLFWwindow* Window)
|
||||
{
|
||||
if (!Window)
|
||||
{
|
||||
Log::Error("Window not initialized.");
|
||||
}
|
||||
|
||||
if (!InstanceManager.GetInstance())
|
||||
{
|
||||
Log::Error("Instance is null.");
|
||||
}
|
||||
|
||||
VkResult result = glfwCreateWindowSurface(InstanceManager.GetInstance(), Window, nullptr, &Surface);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
std::string errorMsg;
|
||||
switch (result)
|
||||
{
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
errorMsg = "VK_ERROR_EXTENSION_NOT_PRESENT - Required extension not present";
|
||||
break;
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
errorMsg = "VK_ERROR_INITIALIZATION_FAILED - Initialization failed";
|
||||
break;
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||
errorMsg = "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR - Native window already in use";
|
||||
break;
|
||||
default:
|
||||
errorMsg = "Unknown error code: " + std::to_string(result);
|
||||
break;
|
||||
}
|
||||
|
||||
Log::Error("Failed to create window surface: " + errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Window surface created successfully.");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanContext::CreateSyncObjects()
|
||||
{
|
||||
ImageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
RenderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
InFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
VkSemaphoreCreateInfo SemaphoreInfo{};
|
||||
SemaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkFenceCreateInfo FenceInfo{};
|
||||
FenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
FenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
if (vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &ImageAvailableSemaphores[i]) != VK_SUCCESS
|
||||
|| vkCreateSemaphore(DeviceManager.GetDevice(), &SemaphoreInfo, nullptr, &RenderFinishedSemaphores[i]) != VK_SUCCESS
|
||||
|| vkCreateFence(DeviceManager.GetDevice(), &FenceInfo, nullptr, &InFlightFences[i]) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create semaphores!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created semaphores");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanContext::DrawFrame()
|
||||
{
|
||||
vkWaitForFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t ImageIndex;
|
||||
VkResult result = vkAcquireNextImageKHR(
|
||||
DeviceManager.GetDevice(),
|
||||
SwapChain.GetSwapChain(),
|
||||
UINT64_MAX,
|
||||
ImageAvailableSemaphores[CurrentFrame],
|
||||
VK_NULL_HANDLE,
|
||||
&ImageIndex);
|
||||
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
RecreateSwapChain();
|
||||
return;
|
||||
}
|
||||
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
Log::Error("Failed to acquire swap chain images!");
|
||||
}
|
||||
|
||||
vkResetFences(DeviceManager.GetDevice(), 1, &InFlightFences[CurrentFrame]);
|
||||
|
||||
vkAcquireNextImageKHR(DeviceManager.GetDevice(), SwapChain.GetSwapChain(), UINT64_MAX, ImageAvailableSemaphores[CurrentFrame], VK_NULL_HANDLE, &ImageIndex);
|
||||
|
||||
vkResetCommandBuffer(CommandBuffers.GetCommandBuffer(CurrentFrame), 0);
|
||||
CommandBuffers.RecordCommandBuffer(
|
||||
CommandBuffers.GetCommandBuffer(CurrentFrame),
|
||||
ImageIndex,
|
||||
VertexBuffer.GetVertexBuffer(),
|
||||
Config.Vertices,
|
||||
RenderPass.GetRenderPass(),
|
||||
SwapChain.GetSwapChainExtent(),
|
||||
GraphicsPipeline.GetGraphicsPipeline(),
|
||||
Framebuffers.GetSwapChainFrameBuffers());
|
||||
|
||||
VkSubmitInfo SubmitInfo{};
|
||||
SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
|
||||
VkSemaphore WaitSemaphores[] = { ImageAvailableSemaphores[CurrentFrame] };
|
||||
VkPipelineStageFlags WaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
SubmitInfo.waitSemaphoreCount = 1;
|
||||
SubmitInfo.pWaitSemaphores = WaitSemaphores;
|
||||
SubmitInfo.pWaitDstStageMask = WaitStages;
|
||||
|
||||
SubmitInfo.commandBufferCount = 1;
|
||||
VkCommandBuffer CommandBuffer = CommandBuffers.GetCommandBuffer(CurrentFrame);
|
||||
SubmitInfo.pCommandBuffers = &CommandBuffer;
|
||||
|
||||
VkSemaphore SignalSemaphores[] = { RenderFinishedSemaphores[CurrentFrame] };
|
||||
SubmitInfo.signalSemaphoreCount = 1;
|
||||
SubmitInfo.pSignalSemaphores = SignalSemaphores;
|
||||
|
||||
if (vkQueueSubmit(DeviceManager.GetGraphicsQueue(), 1, &SubmitInfo, InFlightFences[CurrentFrame]) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to submit draw command buffer!");
|
||||
}
|
||||
|
||||
VkPresentInfoKHR PresentInfo{};
|
||||
PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
PresentInfo.waitSemaphoreCount = 1;
|
||||
PresentInfo.pWaitSemaphores = SignalSemaphores;
|
||||
|
||||
VkSwapchainKHR SwapChains[] = { SwapChain.GetSwapChain() };
|
||||
|
||||
PresentInfo.swapchainCount = 1;
|
||||
PresentInfo.pSwapchains = SwapChains;
|
||||
PresentInfo.pImageIndices = &ImageIndex;
|
||||
PresentInfo.pResults = nullptr;
|
||||
|
||||
result = vkQueuePresentKHR(DeviceManager.GetPresentQueue(), &PresentInfo);
|
||||
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || bFramebufferResized)
|
||||
{
|
||||
bFramebufferResized = false;
|
||||
RecreateSwapChain();
|
||||
}
|
||||
else if (result != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to present swap chain image!");
|
||||
}
|
||||
|
||||
CurrentFrame = (CurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
void VulkanContext::RecreateSwapChain()
|
||||
{
|
||||
int Width = 0, Height = 0;
|
||||
glfwGetFramebufferSize(Config.Window, &Width, &Height);
|
||||
while (Width == 0 || Height == 0)
|
||||
{
|
||||
glfwGetFramebufferSize(Config.Window, &Width, &Height);
|
||||
glfwWaitEvents();
|
||||
}
|
||||
|
||||
Log::Info("Recreating SwapChain...");
|
||||
vkDeviceWaitIdle(DeviceManager.GetDevice());
|
||||
|
||||
CleanupSwapChain();
|
||||
|
||||
SwapChain.CreateSwapChain();
|
||||
SwapChain.CreateImageViews();
|
||||
Framebuffers.CreateFramebuffers();
|
||||
}
|
||||
|
||||
void VulkanContext::CleanupSwapChain()
|
||||
{
|
||||
Framebuffers.Cleanup();
|
||||
SwapChain.Cleanup();
|
||||
}
|
||||
34
src/VulkanDebugManager.cpp → src/private/VulkanDebugManager.cpp
Normal file → Executable file
34
src/VulkanDebugManager.cpp → src/private/VulkanDebugManager.cpp
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
#include "VulkanDebugManager.h"
|
||||
#include "Logger.h"
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
VulkanDebugManager::VulkanDebugManager()
|
||||
{
|
||||
@@ -7,28 +7,6 @@ VulkanDebugManager::VulkanDebugManager()
|
||||
|
||||
VulkanDebugManager::~VulkanDebugManager()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
VulkanDebugManager::VulkanDebugManager(VulkanDebugManager&& Other) noexcept
|
||||
: DebugMessenger(Other.DebugMessenger), Instance(Other.Instance)
|
||||
{
|
||||
Other.DebugMessenger = VK_NULL_HANDLE;
|
||||
Other.Instance = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VulkanDebugManager& VulkanDebugManager::operator=(VulkanDebugManager&& Other) noexcept
|
||||
{
|
||||
if (this != &Other)
|
||||
{
|
||||
Cleanup();
|
||||
DebugMessenger = Other.DebugMessenger;
|
||||
Instance = Other.Instance;
|
||||
Other.DebugMessenger = VK_NULL_HANDLE;
|
||||
Other.Instance = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void VulkanDebugManager::Initialize(VkInstance Instance)
|
||||
@@ -49,12 +27,12 @@ void VulkanDebugManager::Cleanup()
|
||||
return;
|
||||
}
|
||||
|
||||
FDestroyDebugUtilsMessengerExtParams Params = { Instance, DebugMessenger, nullptr };
|
||||
FDestroyParams Params = { Instance, DebugMessenger, nullptr };
|
||||
DestroyDebugUtilsMessengerExt(Params);
|
||||
DebugMessenger = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params)
|
||||
VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateParams& Params)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Params.Instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
if (func != nullptr)
|
||||
@@ -67,7 +45,7 @@ VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateDebugUtil
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params)
|
||||
void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyParams& Params)
|
||||
{
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
Params.Instance,
|
||||
@@ -86,7 +64,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugManager::DebugCallback(
|
||||
void* pUserData)
|
||||
{
|
||||
Log::Validation(pCallbackData->pMessage);
|
||||
// std::cerr << "[Validation layer] : " << pCallbackData->pMessage << std::endl;
|
||||
|
||||
if (MessageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||
{
|
||||
@@ -110,11 +87,10 @@ void VulkanDebugManager::SetupDebugMessanger()
|
||||
|
||||
PopulateDebugMessengerCreateInfo(CreateInfo);
|
||||
|
||||
FCreateDebugUtilsMessengerExtParams Params = { Instance, &CreateInfo, nullptr, &DebugMessenger };
|
||||
FCreateParams Params = { Instance, &CreateInfo, nullptr, &DebugMessenger };
|
||||
|
||||
if (CreateDebugUtilsMessengerExt(Params) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to set up debug messenger!");
|
||||
// throw std::runtime_error("failed to set up debug messenger!");
|
||||
}
|
||||
}
|
||||
247
src/private/VulkanDeviceManager.cpp
Executable file
247
src/private/VulkanDeviceManager.cpp
Executable file
@@ -0,0 +1,247 @@
|
||||
#include "VulkanDeviceManager.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint> // Necessary for uint32_t
|
||||
#include <set>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "VulkanContext.h"
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
VulkanDeviceManager::VulkanDeviceManager()
|
||||
{
|
||||
}
|
||||
|
||||
VulkanDeviceManager::~VulkanDeviceManager()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::Initialize(FDeviceConfig InConfig)
|
||||
// VkInstance Instance,
|
||||
// bool bEnableValidationLayers,
|
||||
// VkSurfaceKHR Surface,
|
||||
// GLFWwindow* Window)
|
||||
{
|
||||
DeviceConfig = InConfig;
|
||||
// this->Instance = Instance;
|
||||
// this->Surface = Surface;
|
||||
// this->bEnableValidationLayers = bEnableValidationLayers;
|
||||
// this->Window = Window;
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::Cleanup()
|
||||
{
|
||||
vkDestroyDevice(Device, nullptr);
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::PickPhysicalDevice()
|
||||
{
|
||||
uint32_t DeviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(DeviceConfig.Instance, &DeviceCount, nullptr);
|
||||
|
||||
if (DeviceCount == 0)
|
||||
{
|
||||
Log::Error("Failed to find GPU with Vulkan Support.");
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> Devices(DeviceCount);
|
||||
vkEnumeratePhysicalDevices(DeviceConfig.Instance, &DeviceCount, Devices.data());
|
||||
|
||||
std::multimap<int, VkPhysicalDevice> Candidates;
|
||||
|
||||
for (const auto& Device : Devices)
|
||||
{
|
||||
if (IsDeviceSuitable(Device))
|
||||
{
|
||||
int Score = RateDeviceSuitability(Device);
|
||||
Candidates.insert(std::make_pair(Score, Device));
|
||||
}
|
||||
}
|
||||
|
||||
if (Candidates.rbegin()->first > 0)
|
||||
{
|
||||
PhysicalDevice = Candidates.rbegin()->second;
|
||||
SwapChainSupport = QuerySwapChainSupport(PhysicalDevice);
|
||||
Log::Info("Suitable GPU found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Error("Failed to find a suitable GPU.");
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanDeviceManager::IsDeviceSuitable(VkPhysicalDevice Device)
|
||||
{
|
||||
QueueFamilyIndices Indices = FindQueueFamilies(Device);
|
||||
|
||||
bool bExtensionsSupported = CheckDeviceExtensionSupport(Device);
|
||||
|
||||
bool bSwapChainAdequate = false;
|
||||
if (bExtensionsSupported)
|
||||
{
|
||||
SwapChainSupport = QuerySwapChainSupport(Device);
|
||||
bSwapChainAdequate = !SwapChainSupport.Formats.empty() && !SwapChainSupport.PresentModes.empty();
|
||||
}
|
||||
|
||||
return Indices.IsComplete() && bExtensionsSupported && bSwapChainAdequate;
|
||||
}
|
||||
|
||||
int VulkanDeviceManager::RateDeviceSuitability(VkPhysicalDevice Device)
|
||||
{
|
||||
VkPhysicalDeviceProperties DeviceProperties;
|
||||
vkGetPhysicalDeviceProperties(Device, &DeviceProperties);
|
||||
|
||||
VkPhysicalDeviceFeatures DeviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(Device, &DeviceFeatures);
|
||||
|
||||
int Score = 0;
|
||||
|
||||
if (DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
{
|
||||
Score += 100;
|
||||
}
|
||||
|
||||
Score += DeviceProperties.limits.maxImageDimension2D;
|
||||
|
||||
if (!DeviceFeatures.geometryShader)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Score;
|
||||
}
|
||||
|
||||
bool VulkanDeviceManager::CheckDeviceExtensionSupport(VkPhysicalDevice Device)
|
||||
{
|
||||
uint32_t ExtensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> AvailableExtensions(ExtensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(Device, nullptr, &ExtensionCount, AvailableExtensions.data());
|
||||
|
||||
std::set<std::string> RequiredExtensions(DeviceExtensions.begin(), DeviceExtensions.end());
|
||||
|
||||
for (const auto& Extension : AvailableExtensions)
|
||||
{
|
||||
RequiredExtensions.erase(Extension.extensionName);
|
||||
}
|
||||
|
||||
return RequiredExtensions.empty();
|
||||
}
|
||||
|
||||
QueueFamilyIndices VulkanDeviceManager::FindQueueFamilies(VkPhysicalDevice Device)
|
||||
{
|
||||
QueueFamilyIndices Indices;
|
||||
|
||||
uint32_t QueueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> QueueFamilies(QueueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilies.data());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& QueueFamily : QueueFamilies)
|
||||
{
|
||||
if (QueueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
Indices.GraphicsFamily = i;
|
||||
}
|
||||
|
||||
VkBool32 PresentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(Device, i, DeviceConfig.Surface, &PresentSupport);
|
||||
|
||||
if (PresentSupport)
|
||||
{
|
||||
Indices.PresentFamily = i;
|
||||
}
|
||||
if (Indices.IsComplete())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return Indices;
|
||||
}
|
||||
|
||||
void VulkanDeviceManager::CreateLogicalDevice()
|
||||
{
|
||||
PhysicalQueueFamilies = FindQueueFamilies(PhysicalDevice);
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> QueueCreateInfos;
|
||||
std::set<uint32_t> UniqueQueueFamilies = { PhysicalQueueFamilies.GraphicsFamily.value(), PhysicalQueueFamilies.PresentFamily.value() };
|
||||
|
||||
float QueuePriority = 1.0f;
|
||||
for (uint32_t QueueFamily : UniqueQueueFamilies)
|
||||
{
|
||||
VkDeviceQueueCreateInfo QueueCreateInfo{};
|
||||
QueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
QueueCreateInfo.queueFamilyIndex = PhysicalQueueFamilies.GraphicsFamily.value();
|
||||
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 (DeviceConfig.bEnableValidationLayers)
|
||||
{
|
||||
CreateInfo.enabledLayerCount = static_cast<uint32_t>(ValidationLayers.size());
|
||||
CreateInfo.ppEnabledLayerNames = ValidationLayers.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInfo.enabledLayerCount = 0;
|
||||
}
|
||||
|
||||
if (vkCreateDevice(PhysicalDevice, &CreateInfo, nullptr, &Device) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create logical device!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Created logical device.");
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(Device, PhysicalQueueFamilies.GraphicsFamily.value(), 0, &GraphicsQueue);
|
||||
vkGetDeviceQueue(Device, PhysicalQueueFamilies.PresentFamily.value(), 0, &PresentQueue);
|
||||
}
|
||||
|
||||
SwapChainSupportDetails VulkanDeviceManager::QuerySwapChainSupport(VkPhysicalDevice Device)
|
||||
{
|
||||
SwapChainSupportDetails Details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device, DeviceConfig.Surface, &Details.Capabilities);
|
||||
|
||||
uint32_t FormatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(Device, DeviceConfig.Surface, &FormatCount, nullptr);
|
||||
|
||||
if (FormatCount != 0)
|
||||
{
|
||||
Details.Formats.resize(FormatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(Device, DeviceConfig.Surface, &FormatCount, Details.Formats.data());
|
||||
}
|
||||
|
||||
uint32_t PresentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(Device, DeviceConfig.Surface, &PresentModeCount, nullptr);
|
||||
|
||||
if (PresentModeCount != 0)
|
||||
{
|
||||
Details.PresentModes.resize(PresentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(Device, DeviceConfig.Surface, &PresentModeCount, Details.PresentModes.data());
|
||||
}
|
||||
|
||||
return Details;
|
||||
}
|
||||
48
src/private/VulkanFramebuffers.cpp
Normal file
48
src/private/VulkanFramebuffers.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "VulkanFramebuffers.h"
|
||||
|
||||
#include "utilities/Logger.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
void VulkanFramebuffers::Initialize(FFramebufferConfig InConfig)
|
||||
{
|
||||
FramebufferConfig = InConfig;
|
||||
}
|
||||
|
||||
void VulkanFramebuffers::Cleanup()
|
||||
{
|
||||
for (auto Framebuffer : SwapChainFramebuffers)
|
||||
{
|
||||
vkDestroyFramebuffer(FramebufferConfig.Device, Framebuffer, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// void VulkanFramebuffers::CreateFramebuffers(VkRenderPass RenderPass, std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent)
|
||||
void VulkanFramebuffers::CreateFramebuffers()
|
||||
{
|
||||
SwapChainFramebuffers.resize(FramebufferConfig.SwapChainImageViews.size());
|
||||
|
||||
for (size_t i = 0; i < FramebufferConfig.SwapChainImageViews.size(); i++)
|
||||
{
|
||||
VkImageView Attachments[] = {
|
||||
FramebufferConfig.SwapChainImageViews[i]
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo FramebufferInfo{};
|
||||
FramebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
FramebufferInfo.renderPass = FramebufferConfig.RenderPass;
|
||||
FramebufferInfo.attachmentCount = 1;
|
||||
FramebufferInfo.pAttachments = Attachments;
|
||||
FramebufferInfo.width = FramebufferConfig.SwapChainExtent.width;
|
||||
FramebufferInfo.height = FramebufferConfig.SwapChainExtent.height;
|
||||
FramebufferInfo.layers = 1;
|
||||
|
||||
if (vkCreateFramebuffer(FramebufferConfig.Device, &FramebufferInfo, nullptr, &SwapChainFramebuffers[i]) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create frame buffer!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created framebuffers.");
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/VulkanInstanceManager.cpp → src/private/VulkanInstanceManager.cpp
Normal file → Executable file
111
src/VulkanInstanceManager.cpp → src/private/VulkanInstanceManager.cpp
Normal file → Executable file
@@ -1,6 +1,8 @@
|
||||
#include "VulkanInstanceManager.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "utilities/Logger.h"
|
||||
#include <cstring>
|
||||
|
||||
VulkanInstanceManager::VulkanInstanceManager()
|
||||
{
|
||||
@@ -8,107 +10,14 @@ VulkanInstanceManager::VulkanInstanceManager()
|
||||
|
||||
VulkanInstanceManager::~VulkanInstanceManager()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
VulkanInstanceManager::VulkanInstanceManager(VulkanInstanceManager&& Other) noexcept
|
||||
: Instance(Other.Instance) /*, bValidationEnabled(Other.bValidationEnabled), bVerboseLogging(Other.bVerboseLogging), VkDebugManager(std::move(Other.VkDebugManager))*/
|
||||
{
|
||||
Other.Instance = VK_NULL_HANDLE;
|
||||
Other.bValidationEnabled = false;
|
||||
Other.bVerboseLogging = false;
|
||||
}
|
||||
|
||||
VulkanInstanceManager& VulkanInstanceManager::operator=(VulkanInstanceManager&& Other) noexcept
|
||||
{
|
||||
if (this != &Other)
|
||||
{
|
||||
Cleanup();
|
||||
Instance = Other.Instance;
|
||||
bValidationEnabled = Other.bValidationEnabled;
|
||||
bVerboseLogging = Other.bVerboseLogging;
|
||||
VkDebugManager = std::move(Other.VkDebugManager);
|
||||
|
||||
Other.Instance = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// void VulkanInstanceManager::Initialize(const FVulkanConfig& Config)
|
||||
//{
|
||||
// if (IsInitialized())
|
||||
// {
|
||||
// Log::Warning("Already Initialized.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// bValidationEnabled = Config.bValidationEnabled;
|
||||
// bVerboseLogging = Config.bVerboseLogging;
|
||||
//
|
||||
// if (bValidationEnabled)
|
||||
// {
|
||||
// Log::Info("DebugManager created with validation enabled.");
|
||||
// VkDebugManager = std::make_unique<VulkanDebugManager>();
|
||||
// }
|
||||
//
|
||||
// CreateInstance();
|
||||
// }
|
||||
|
||||
void VulkanInstanceManager::Initialize(bool bEnableValidationLayers)
|
||||
{
|
||||
if (IsInitialized())
|
||||
{
|
||||
Log::Warning("Already Initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bEnableValidationLayers)
|
||||
{
|
||||
Log::Info("DebugManager created with validation enabled.");
|
||||
VkDebugManager = std::make_unique<VulkanDebugManager>();
|
||||
}
|
||||
|
||||
CreateInstance();
|
||||
}
|
||||
|
||||
void VulkanInstanceManager::SetupDebug()
|
||||
{
|
||||
if (bValidationEnabled)
|
||||
{
|
||||
VkDebugManager->Initialize(Instance);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanInstanceManager::SetupDevice()
|
||||
{
|
||||
VkDeviceManager = std::make_unique<VulkanDeviceManager>();
|
||||
VkDeviceManager->Initialize(Instance, bValidationEnabled, ValidationLayers);
|
||||
}
|
||||
|
||||
void VulkanInstanceManager::Cleanup()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
{
|
||||
Log::Warning("Not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (VkDeviceManager)
|
||||
{
|
||||
VkDeviceManager->Cleanup();
|
||||
}
|
||||
|
||||
if (VkDebugManager)
|
||||
{
|
||||
VkDebugManager->Cleanup();
|
||||
}
|
||||
|
||||
vkDestroyInstance(Instance, nullptr);
|
||||
Instance = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
std::vector<const char*> VulkanInstanceManager::GetRequiredExtensions()
|
||||
std::vector<const char*> VulkanInstanceManager::GetRequiredExtensions(bool bEnableValidationLayers)
|
||||
{
|
||||
uint32_t GlfwExtensionCount = 0;
|
||||
const char** GlfwExtensions;
|
||||
@@ -116,7 +25,7 @@ std::vector<const char*> VulkanInstanceManager::GetRequiredExtensions()
|
||||
|
||||
std::vector<const char*> Extensions(GlfwExtensions, GlfwExtensions + GlfwExtensionCount);
|
||||
|
||||
if (VkDebugManager)
|
||||
if (bEnableValidationLayers)
|
||||
{
|
||||
Extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
@@ -154,11 +63,11 @@ bool VulkanInstanceManager::CheckValidationLayerSupport()
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanInstanceManager::CreateInstance()
|
||||
void VulkanInstanceManager::CreateInstance(VulkanDebugManager* DebugManager)
|
||||
{
|
||||
Log::Info("Creating Vulkan instance.");
|
||||
|
||||
if (bValidationEnabled && !CheckValidationLayerSupport())
|
||||
if (DebugManager && !CheckValidationLayerSupport())
|
||||
{
|
||||
Log::Error("Validation layers requested, but not available!");
|
||||
}
|
||||
@@ -175,17 +84,17 @@ void VulkanInstanceManager::CreateInstance()
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
CreateInfo.pApplicationInfo = &AppInfo;
|
||||
|
||||
auto Extensions = GetRequiredExtensions();
|
||||
auto Extensions = GetRequiredExtensions(DebugManager != nullptr);
|
||||
CreateInfo.enabledExtensionCount = static_cast<uint32_t>(Extensions.size());
|
||||
CreateInfo.ppEnabledExtensionNames = Extensions.data();
|
||||
|
||||
if (VkDebugManager)
|
||||
if (DebugManager)
|
||||
{
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
|
||||
CreateInfo.enabledLayerCount = static_cast<uint32_t>(ValidationLayers.size());
|
||||
CreateInfo.ppEnabledLayerNames = ValidationLayers.data();
|
||||
|
||||
VkDebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
DebugManager->PopulateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
CreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
|
||||
}
|
||||
else
|
||||
275
src/private/VulkanPipeline.cpp
Executable file
275
src/private/VulkanPipeline.cpp
Executable file
@@ -0,0 +1,275 @@
|
||||
#include "VulkanPipeline.h"
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "utilities/FileReader.h"
|
||||
#include "utilities/Logger.h"
|
||||
#include "Primitives.h"
|
||||
|
||||
void VulkanPipeline::Initialize(VkDevice InDevice)
|
||||
{
|
||||
Device = InDevice;
|
||||
}
|
||||
|
||||
void VulkanPipeline::Cleanup()
|
||||
{
|
||||
// for (auto Framebuffer : SwapChainFrameBuffers)
|
||||
// {
|
||||
// vkDestroyFramebuffer(Device, Framebuffer, nullptr);
|
||||
// }
|
||||
|
||||
vkDestroyPipeline(Device, GraphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(Device, PipelineLayout, nullptr);
|
||||
}
|
||||
|
||||
void VulkanPipeline::CreateGraphicsPipeline(VkExtent2D SwapChainExtent, VkRenderPass RenderPass)
|
||||
{
|
||||
auto VertShaderCode = ReadFile("Shaders/vert.spv");
|
||||
auto FragShaderCode = ReadFile("Shaders/frag.spv");
|
||||
|
||||
Log::Info("Vert buffer size: " + std::to_string(VertShaderCode.size()));
|
||||
Log::Info("Frag buffer size: " + std::to_string(FragShaderCode.size()));
|
||||
|
||||
VkShaderModule VertShaderModule = CreateShaderModule(VertShaderCode);
|
||||
VkShaderModule FragShaderModule = CreateShaderModule(FragShaderCode);
|
||||
|
||||
VkPipelineShaderStageCreateInfo VertShaderStageInfo{};
|
||||
VertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
VertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
VertShaderStageInfo.module = VertShaderModule;
|
||||
VertShaderStageInfo.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo FragShaderStageInfo{};
|
||||
FragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
FragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
FragShaderStageInfo.module = FragShaderModule;
|
||||
FragShaderStageInfo.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo ShaderStages[] = { VertShaderStageInfo, FragShaderStageInfo };
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo VertexInputInfo{};
|
||||
VertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
|
||||
auto BindingDescription = Vertex::GetBindingDescription();
|
||||
auto AttributeDescriptions = Vertex::GetAttributeDescriptions();
|
||||
|
||||
VertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||
VertexInputInfo.pVertexBindingDescriptions = &BindingDescription;
|
||||
VertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(AttributeDescriptions.size());
|
||||
VertexInputInfo.pVertexAttributeDescriptions = AttributeDescriptions.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo InputAssembly{};
|
||||
InputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
InputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
InputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
// VkViewport Viewport{};
|
||||
// Viewport.x = 0.0f;
|
||||
// Viewport.x = 0.0f;
|
||||
// Viewport.width = SwapChainExtent.width;
|
||||
// Viewport.height = SwapChainExtent.height;
|
||||
// Viewport.minDepth = 0.0f;
|
||||
// Viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D Scissor{};
|
||||
Scissor.offset = { 0, 0 };
|
||||
Scissor.extent = SwapChainExtent;
|
||||
|
||||
std::vector<VkDynamicState> DynamicStates = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo DynamicState{};
|
||||
DynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
DynamicState.dynamicStateCount = static_cast<uint32_t>(DynamicStates.size());
|
||||
DynamicState.pDynamicStates = DynamicStates.data();
|
||||
|
||||
VkPipelineViewportStateCreateInfo ViewportState{};
|
||||
ViewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
ViewportState.viewportCount = 1;
|
||||
ViewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo Rasterizer{};
|
||||
Rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
Rasterizer.depthClampEnable = VK_FALSE;
|
||||
Rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
Rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
Rasterizer.lineWidth = 1.0f;
|
||||
Rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
Rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
Rasterizer.depthBiasEnable = VK_FALSE;
|
||||
Rasterizer.depthBiasConstantFactor = 0.0f;
|
||||
Rasterizer.depthBiasClamp = 0.0f;
|
||||
Rasterizer.depthBiasSlopeFactor = 0.0f;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo Multisampling{};
|
||||
Multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
Multisampling.sampleShadingEnable = VK_FALSE;
|
||||
Multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
Multisampling.minSampleShading = 1.0f;
|
||||
Multisampling.pSampleMask = nullptr;
|
||||
Multisampling.alphaToCoverageEnable = VK_FALSE;
|
||||
Multisampling.alphaToOneEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState ColorBlendAttachement{};
|
||||
ColorBlendAttachement.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
ColorBlendAttachement.blendEnable = VK_FALSE;
|
||||
ColorBlendAttachement.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
ColorBlendAttachement.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
ColorBlendAttachement.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
ColorBlendAttachement.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
ColorBlendAttachement.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
ColorBlendAttachement.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo ColorBlending{};
|
||||
ColorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
ColorBlending.logicOpEnable = VK_FALSE;
|
||||
ColorBlending.logicOp = VK_LOGIC_OP_COPY;
|
||||
ColorBlending.attachmentCount = 1;
|
||||
ColorBlending.pAttachments = &ColorBlendAttachement;
|
||||
ColorBlending.blendConstants[0] = 0.0f;
|
||||
ColorBlending.blendConstants[1] = 0.0f;
|
||||
ColorBlending.blendConstants[2] = 0.0f;
|
||||
ColorBlending.blendConstants[3] = 0.0f;
|
||||
|
||||
VkPipelineLayoutCreateInfo PipelineLayoutInfo{};
|
||||
PipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
PipelineLayoutInfo.setLayoutCount = 0;
|
||||
PipelineLayoutInfo.pSetLayouts = nullptr;
|
||||
PipelineLayoutInfo.pushConstantRangeCount = 0;
|
||||
PipelineLayoutInfo.pPushConstantRanges = nullptr;
|
||||
|
||||
if (vkCreatePipelineLayout(Device, &PipelineLayoutInfo, nullptr, &PipelineLayout) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create pipeline layout!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created pipeline layout");
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo PipelineInfo{};
|
||||
PipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
PipelineInfo.stageCount = 2;
|
||||
PipelineInfo.pStages = ShaderStages;
|
||||
PipelineInfo.pVertexInputState = &VertexInputInfo;
|
||||
PipelineInfo.pInputAssemblyState = &InputAssembly;
|
||||
PipelineInfo.pViewportState = &ViewportState;
|
||||
PipelineInfo.pRasterizationState = &Rasterizer;
|
||||
PipelineInfo.pMultisampleState = &Multisampling;
|
||||
PipelineInfo.pDepthStencilState = nullptr;
|
||||
PipelineInfo.pColorBlendState = &ColorBlending;
|
||||
PipelineInfo.pDynamicState = &DynamicState;
|
||||
PipelineInfo.layout = PipelineLayout;
|
||||
PipelineInfo.renderPass = RenderPass;
|
||||
PipelineInfo.subpass = 0;
|
||||
PipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
PipelineInfo.basePipelineIndex = -1;
|
||||
|
||||
if (vkCreateGraphicsPipelines(Device, VK_NULL_HANDLE, 1, &PipelineInfo, nullptr, &GraphicsPipeline) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create graphics pipeline!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created graphics pipeline.");
|
||||
}
|
||||
|
||||
vkDestroyShaderModule(Device, FragShaderModule, nullptr);
|
||||
vkDestroyShaderModule(Device, VertShaderModule, nullptr);
|
||||
}
|
||||
|
||||
VkShaderModule VulkanPipeline::CreateShaderModule(const std::vector<char>& Code)
|
||||
{
|
||||
VkShaderModuleCreateInfo CreateInfo{};
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
CreateInfo.codeSize = Code.size();
|
||||
CreateInfo.pCode = reinterpret_cast<const uint32_t*>(Code.data());
|
||||
|
||||
VkShaderModule ShaderModule;
|
||||
if (vkCreateShaderModule(Device, &CreateInfo, nullptr, &ShaderModule) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create shader module.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created shader module.");
|
||||
}
|
||||
|
||||
return ShaderModule;
|
||||
}
|
||||
|
||||
// void VulkanPipeline::CreateRenderPass(VkFormat SwapChainImageFormat)
|
||||
// {
|
||||
// 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;
|
||||
//
|
||||
// VkRenderPassCreateInfo RenderPassInfo{};
|
||||
// RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
// RenderPassInfo.attachmentCount = 1;
|
||||
// RenderPassInfo.pAttachments = &ColorAttachment;
|
||||
// RenderPassInfo.subpassCount = 1;
|
||||
// RenderPassInfo.pSubpasses = &Subpass;
|
||||
//
|
||||
// VkSubpassDependency Dependency{};
|
||||
// Dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
// Dependency.dstSubpass = 0;
|
||||
// Dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
// Dependency.srcAccessMask = 0;
|
||||
// Dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
// Dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
// RenderPassInfo.dependencyCount = 1;
|
||||
// RenderPassInfo.pDependencies = &Dependency;
|
||||
//
|
||||
// if (vkCreateRenderPass(Device, &RenderPassInfo, nullptr, &RenderPass) != VK_SUCCESS)
|
||||
// {
|
||||
// Log::Error("Failed to create render pass!");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Log::Info("Successfully created render pass.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// void VulkanPipeline::CreateFramebuffers(std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent)
|
||||
// {
|
||||
// SwapChainFrameBuffers.resize(SwapChainImageViews.size());
|
||||
//
|
||||
// for (size_t i = 0; i < SwapChainImageViews.size(); i++)
|
||||
// {
|
||||
// VkImageView Attachments[] = {
|
||||
// SwapChainImageViews[i]
|
||||
// };
|
||||
//
|
||||
// VkFramebufferCreateInfo FramebufferInfo{};
|
||||
// FramebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
// FramebufferInfo.renderPass = RenderPass;
|
||||
// FramebufferInfo.attachmentCount = 1;
|
||||
// FramebufferInfo.pAttachments = Attachments;
|
||||
// FramebufferInfo.width = SwapChainExtent.width;
|
||||
// FramebufferInfo.height = SwapChainExtent.height;
|
||||
// FramebufferInfo.layers = 1;
|
||||
//
|
||||
// if (vkCreateFramebuffer(Device, &FramebufferInfo, nullptr, &SwapChainFrameBuffers[i]) != VK_SUCCESS)
|
||||
// {
|
||||
// Log::Error("Failed to create frame buffer!");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
60
src/private/VulkanRenderPass.cpp
Normal file
60
src/private/VulkanRenderPass.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "VulkanRenderPass.h"
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
void VulkanRenderPass::Initialize(VkDevice InDevice)
|
||||
{
|
||||
Device = InDevice;
|
||||
}
|
||||
|
||||
void VulkanRenderPass::Cleanup()
|
||||
{
|
||||
vkDestroyRenderPass(Device, RenderPass, nullptr);
|
||||
}
|
||||
|
||||
void VulkanRenderPass::CreateRenderPass(VkFormat SwapChainImageFormat)
|
||||
{
|
||||
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;
|
||||
|
||||
VkRenderPassCreateInfo RenderPassInfo{};
|
||||
RenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
RenderPassInfo.attachmentCount = 1;
|
||||
RenderPassInfo.pAttachments = &ColorAttachment;
|
||||
RenderPassInfo.subpassCount = 1;
|
||||
RenderPassInfo.pSubpasses = &Subpass;
|
||||
|
||||
VkSubpassDependency Dependency{};
|
||||
Dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
Dependency.dstSubpass = 0;
|
||||
Dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
Dependency.srcAccessMask = 0;
|
||||
Dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
Dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
RenderPassInfo.dependencyCount = 1;
|
||||
RenderPassInfo.pDependencies = &Dependency;
|
||||
|
||||
if (vkCreateRenderPass(Device, &RenderPassInfo, nullptr, &RenderPass) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create render pass!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created render pass.");
|
||||
}
|
||||
}
|
||||
203
src/private/VulkanSwapChain.cpp
Normal file
203
src/private/VulkanSwapChain.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
#include "VulkanSwapChain.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint> // Necessary for uint32_t
|
||||
#include <limits> // Necessary for std::numeric_limits
|
||||
#include <algorithm> // Necessary for std::clamp
|
||||
#include <set>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
VulkanSwapChain::VulkanSwapChain()
|
||||
{
|
||||
}
|
||||
|
||||
VulkanSwapChain::~VulkanSwapChain()
|
||||
{
|
||||
// Cleanup();
|
||||
}
|
||||
|
||||
void VulkanSwapChain::Initialize(FSwapConfig InSwapConfig)
|
||||
{
|
||||
SwapConfig = InSwapConfig;
|
||||
}
|
||||
|
||||
// void VulkanSwapChain::Initialize(
|
||||
// VkDevice InDevice,
|
||||
// VkSurfaceKHR InSurface,
|
||||
// GLFWwindow* InWindow)
|
||||
// {
|
||||
// Device = InDevice;
|
||||
// Surface = InSurface;
|
||||
// Window = InWindow;
|
||||
// }
|
||||
|
||||
void VulkanSwapChain::Cleanup()
|
||||
{
|
||||
for (auto ImageView : SwapChainImageViews)
|
||||
{
|
||||
vkDestroyImageView(SwapConfig.Device, ImageView, nullptr);
|
||||
}
|
||||
vkDestroySwapchainKHR(SwapConfig.Device, SwapChain, nullptr);
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR VulkanSwapChain::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats)
|
||||
{
|
||||
for (const auto& AvailableFormat : AvailableFormats)
|
||||
{
|
||||
if (AvailableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && AvailableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
{
|
||||
return AvailableFormat;
|
||||
}
|
||||
}
|
||||
return AvailableFormats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR VulkanSwapChain::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes)
|
||||
{
|
||||
for (const auto& AvailablePresentMode : AvailablePresentModes)
|
||||
{
|
||||
if (AvailablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
{
|
||||
return AvailablePresentMode;
|
||||
}
|
||||
}
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkExtent2D VulkanSwapChain::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities)
|
||||
{
|
||||
if (Capabilities.currentExtent.width != (std::numeric_limits<uint32_t>::max)())
|
||||
{
|
||||
return Capabilities.currentExtent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SwapConfig.Window == nullptr)
|
||||
{
|
||||
Log::Error("GLFW window is null in CreateSwapChain!");
|
||||
}
|
||||
int Width, Height;
|
||||
glfwGetFramebufferSize(SwapConfig.Window, &Width, &Height);
|
||||
|
||||
VkExtent2D ActualExtent = {
|
||||
static_cast<uint32_t>(Width),
|
||||
static_cast<uint32_t>(Height)
|
||||
};
|
||||
|
||||
ActualExtent.width = std::clamp(ActualExtent.width, Capabilities.minImageExtent.width, Capabilities.maxImageExtent.width);
|
||||
ActualExtent.height = std::clamp(ActualExtent.height, Capabilities.minImageExtent.height, Capabilities.maxImageExtent.height);
|
||||
|
||||
return ActualExtent;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanSwapChain::CreateSwapChain()
|
||||
{
|
||||
VkSurfaceFormatKHR SurfaceFormat = ChooseSwapSurfaceFormat(SwapConfig.Formats);
|
||||
VkPresentModeKHR PresentMode = ChooseSwapPresentMode(SwapConfig.PresentModes);
|
||||
VkExtent2D Extent = ChooseSwapExtent(SwapConfig.Capabilities);
|
||||
|
||||
uint32_t ImageCount = SwapConfig.Capabilities.minImageCount + 1;
|
||||
|
||||
if (SwapConfig.Capabilities.maxImageCount > 0 && ImageCount > SwapConfig.Capabilities.maxImageCount)
|
||||
{
|
||||
ImageCount = SwapConfig.Capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR CreateInfo{};
|
||||
CreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
CreateInfo.surface = SwapConfig.Surface;
|
||||
|
||||
CreateInfo.minImageCount = ImageCount;
|
||||
CreateInfo.imageFormat = SurfaceFormat.format;
|
||||
CreateInfo.imageColorSpace = SurfaceFormat.colorSpace;
|
||||
CreateInfo.imageExtent = Extent;
|
||||
CreateInfo.imageArrayLayers = 1;
|
||||
CreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // may need VK_IMAGE_USAGE_TRANSFER_DST_BIT for post processing https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain#:~:text=VK%5FIMAGE%5FUSAGE%5FTRANSFER%5FDST%5FBIT
|
||||
|
||||
uint32_t QueueFamilyIndices[] = { SwapConfig.GraphicsFamily.value(),
|
||||
SwapConfig.PresentFamily.value() };
|
||||
|
||||
if (SwapConfig.GraphicsFamily != SwapConfig.PresentFamily)
|
||||
{
|
||||
CreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
CreateInfo.queueFamilyIndexCount = 2;
|
||||
CreateInfo.pQueueFamilyIndices = QueueFamilyIndices;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
CreateInfo.queueFamilyIndexCount = 0;
|
||||
CreateInfo.pQueueFamilyIndices = nullptr;
|
||||
}
|
||||
|
||||
CreateInfo.preTransform = SwapConfig.Capabilities.currentTransform;
|
||||
CreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
CreateInfo.presentMode = PresentMode;
|
||||
CreateInfo.clipped = VK_TRUE;
|
||||
CreateInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
Log::Info("ChooseSwapExtent 3");
|
||||
if (vkCreateSwapchainKHR(SwapConfig.Device, &CreateInfo, nullptr, &SwapChain) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create swap chain.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created swap chain.");
|
||||
}
|
||||
|
||||
vkGetSwapchainImagesKHR(SwapConfig.Device, SwapChain, &ImageCount, nullptr);
|
||||
SwapChainImages.resize(ImageCount);
|
||||
vkGetSwapchainImagesKHR(SwapConfig.Device, SwapChain, &ImageCount, SwapChainImages.data());
|
||||
|
||||
SwapChainImageFormat = SurfaceFormat.format;
|
||||
SwapChainExtent = Extent;
|
||||
}
|
||||
|
||||
void VulkanSwapChain::CreateImageViews()
|
||||
{
|
||||
SwapChainImageViews.resize(SwapChainImages.size());
|
||||
|
||||
int CreatedViews = 0;
|
||||
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;
|
||||
|
||||
if (vkCreateImageView(SwapConfig.Device, &CreateInfo, nullptr, &SwapChainImageViews[i]) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create image views.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatedViews++;
|
||||
}
|
||||
}
|
||||
|
||||
Log::Info("Successfully created " + std::to_string(CreatedViews) + " image views.");
|
||||
}
|
||||
|
||||
// void VulkanSwapChain::RecreateSwapChain()
|
||||
// {
|
||||
// vkDeviceWaitIdle(SwapConfig.Device);
|
||||
//
|
||||
// CreateSwapChain();
|
||||
// CreateImageViews();
|
||||
// }
|
||||
74
src/private/VulkanVertexBuffer.cpp
Normal file
74
src/private/VulkanVertexBuffer.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "VulkanVertexBuffer.h"
|
||||
#include "utilities/Logger.h"
|
||||
#include <cstdint>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <cstring>
|
||||
|
||||
void VulkanVertexBuffer::Initialize(FVertexBufferConfig InConfig)
|
||||
{
|
||||
Config = InConfig;
|
||||
}
|
||||
|
||||
void VulkanVertexBuffer::Cleanup()
|
||||
{
|
||||
vkDestroyBuffer(Config.Device, VertexBuffer, nullptr);
|
||||
vkFreeMemory(Config.Device, VertexBufferMemory, nullptr);
|
||||
}
|
||||
|
||||
void VulkanVertexBuffer::CreateVertexBuffer(std::vector<Vertex> InVertices)
|
||||
{
|
||||
VkBufferCreateInfo BufferInfo{};
|
||||
BufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
BufferInfo.size = sizeof(InVertices[0]) * InVertices.size();
|
||||
BufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
BufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateBuffer(Config.Device, &BufferInfo, nullptr, &VertexBuffer) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to create vertex buffer!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully created vertex buffer.");
|
||||
}
|
||||
|
||||
VkMemoryRequirements MemoryRequirements;
|
||||
vkGetBufferMemoryRequirements(Config.Device, VertexBuffer, &MemoryRequirements);
|
||||
|
||||
VkMemoryAllocateInfo AllocateInfo{};
|
||||
AllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
AllocateInfo.allocationSize = MemoryRequirements.size;
|
||||
AllocateInfo.memoryTypeIndex = FindMemoryType(MemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
if (vkAllocateMemory(Config.Device, &AllocateInfo, nullptr, &VertexBufferMemory) != VK_SUCCESS)
|
||||
{
|
||||
Log::Error("Failed to allocate vertex buffer memory!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Info("Successfully allocated vertex buffer memory.");
|
||||
}
|
||||
|
||||
vkBindBufferMemory(Config.Device, VertexBuffer, VertexBufferMemory, 0);
|
||||
|
||||
void* Data;
|
||||
vkMapMemory(Config.Device, VertexBufferMemory, 0, BufferInfo.size, 0, &Data);
|
||||
memcpy(Data, InVertices.data(), (size_t)BufferInfo.size);
|
||||
vkUnmapMemory(Config.Device, VertexBufferMemory);
|
||||
}
|
||||
|
||||
uint32_t VulkanVertexBuffer::FindMemoryType(uint32_t TypeFilter, VkMemoryPropertyFlags Properties)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties MemoryProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(Config.PhysicalDevice, &MemoryProperties);
|
||||
|
||||
for (uint32_t i = 0; i < MemoryProperties.memoryTypeCount; i++)
|
||||
{
|
||||
if ((TypeFilter & (1 << i)) && (MemoryProperties.memoryTypes[i].propertyFlags & Properties) == Properties)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
Log::Error("Failed to find suitable memory type!");
|
||||
}
|
||||
24
src/GlfwWindowManager.h → src/public/GlfwWindowManager.h
Normal file → Executable file
24
src/GlfwWindowManager.h → src/public/GlfwWindowManager.h
Normal file → Executable file
@@ -2,11 +2,11 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
struct FWindowConfig
|
||||
{
|
||||
@@ -23,26 +23,19 @@ public:
|
||||
GlfwWindowManager();
|
||||
~GlfwWindowManager();
|
||||
|
||||
// GlfwWindowManager(const GlfwWindowManager&) = delete;
|
||||
// GlfwWindowManager& operator=(const GlfwWindowManager&) = delete;
|
||||
|
||||
// GlfwWindowManager(GlfwWindowManager&& Other) noexcept;
|
||||
// GlfwWindowManager& operator=(GlfwWindowManager&& Other) noexcept;
|
||||
|
||||
void Initialize(const FWindowConfig& Config);
|
||||
void Cleanup(VkInstance Instance);
|
||||
void Cleanup();
|
||||
|
||||
bool ShouldClose() const;
|
||||
void PollEvents();
|
||||
void WaitEvents() const;
|
||||
void SetTitle(const std::string& Title);
|
||||
|
||||
GLFWwindow* GetHandle() const { return Window; }
|
||||
uint32_t GetWidth() const { return Config.Width; }
|
||||
uint32_t GetHeight() const { return Config.Height; }
|
||||
const std::string& GetTitle() const { return Config.Title; }
|
||||
|
||||
bool IsInitialized() const { return Window && Surface; }
|
||||
bool IsInitialized() const { return Window; }
|
||||
|
||||
void SetResizeCallback(GLFWwindowsizefun Callback);
|
||||
void SetKeyCallback(GLFWkeyfun Callback);
|
||||
@@ -50,16 +43,11 @@ public:
|
||||
void SetCursorPositionCallback(GLFWcursorposfun Callback);
|
||||
void SetScrollCallback(GLFWscrollfun Callback);
|
||||
|
||||
void CreateSurface(VkInstance Instance);
|
||||
|
||||
static VkSurfaceKHR Surface;
|
||||
|
||||
static GLFWwindow* Window;
|
||||
GLFWwindow* GetWindow() const { return Window; }
|
||||
|
||||
private:
|
||||
FWindowConfig Config;
|
||||
|
||||
// VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
GLFWwindow* Window;
|
||||
|
||||
void InitializeGlfw();
|
||||
|
||||
36
src/public/Primitives.h
Normal file
36
src/public/Primitives.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec2 Position;
|
||||
glm::vec3 Color;
|
||||
|
||||
static VkVertexInputBindingDescription GetBindingDescription()
|
||||
{
|
||||
VkVertexInputBindingDescription BindingDescription{};
|
||||
BindingDescription.binding = 0;
|
||||
BindingDescription.stride = sizeof(Vertex);
|
||||
BindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
return BindingDescription;
|
||||
}
|
||||
|
||||
static std::array<VkVertexInputAttributeDescription, 2> GetAttributeDescriptions()
|
||||
{
|
||||
std::array<VkVertexInputAttributeDescription, 2> AttributeDescriptions{};
|
||||
AttributeDescriptions[0].binding = 0;
|
||||
AttributeDescriptions[0].location = 0;
|
||||
AttributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
AttributeDescriptions[0].offset = offsetof(Vertex, Position);
|
||||
|
||||
AttributeDescriptions[1].binding = 0;
|
||||
AttributeDescriptions[1].location = 1;
|
||||
AttributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
AttributeDescriptions[1].offset = offsetof(Vertex, Color);
|
||||
|
||||
return AttributeDescriptions;
|
||||
}
|
||||
};
|
||||
45
src/public/VulkanCommandBuffers.h
Normal file
45
src/public/VulkanCommandBuffers.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VulkanVertexBuffer.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
class VulkanCommandBuffers
|
||||
{
|
||||
public:
|
||||
void Initialize(
|
||||
VkDevice InDevice,
|
||||
VkRenderPass InRenderPass);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateCommandPool(std::optional<uint32_t> GraphicsFamily);
|
||||
|
||||
void CreateCommandBuffers(int FramesInFlight);
|
||||
|
||||
void RecordCommandBuffer(
|
||||
VkCommandBuffer InCommandBuffer,
|
||||
uint32_t ImageIndex,
|
||||
VkBuffer InVertexBuffer,
|
||||
std::vector<Vertex> InVertices,
|
||||
VkRenderPass RenderPass,
|
||||
VkExtent2D SwapChainExtent,
|
||||
VkPipeline GraphicsPipeline,
|
||||
std::vector<VkFramebuffer> SwapChainFramebuffers);
|
||||
|
||||
std::vector<VkCommandBuffer> GetCommandBuffers() { return CommandBuffers; }
|
||||
VkCommandBuffer GetCommandBuffer(int i) { return CommandBuffers[i]; }
|
||||
|
||||
private:
|
||||
VkDevice Device;
|
||||
VkRenderPass RenderPass;
|
||||
VkQueue GraphicsQueue;
|
||||
|
||||
std::vector<VkCommandBuffer> CommandBuffers;
|
||||
VkCommandPool CommandPool;
|
||||
};
|
||||
77
src/public/VulkanContext.h
Executable file
77
src/public/VulkanContext.h
Executable file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "VulkanCommandBuffers.h"
|
||||
#include "VulkanFramebuffers.h"
|
||||
#include "VulkanInstanceManager.h"
|
||||
#include "VulkanDeviceManager.h"
|
||||
#include "VulkanDebugManager.h"
|
||||
#include "VulkanPipeline.h"
|
||||
#include "VulkanRenderPass.h"
|
||||
#include "VulkanSwapChain.h"
|
||||
#include "VulkanVertexBuffer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
static const std::vector<const char*> ValidationLayers = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
|
||||
struct FVulkanConfig
|
||||
{
|
||||
bool bValidationEnabled = true;
|
||||
bool bVerboseLogging = false;
|
||||
GLFWwindow* Window = nullptr;
|
||||
std::vector<Vertex> Vertices;
|
||||
};
|
||||
|
||||
static FVulkanConfig Config = {};
|
||||
|
||||
class VulkanContext
|
||||
{
|
||||
public:
|
||||
VulkanContext();
|
||||
~VulkanContext();
|
||||
|
||||
void Initialize(FVulkanConfig& InConfig);
|
||||
void Cleanup();
|
||||
|
||||
void CreateSurface(GLFWwindow* Window);
|
||||
void CreateSyncObjects();
|
||||
void DrawFrame();
|
||||
void RecreateSwapChain();
|
||||
void CleanupSwapChain();
|
||||
|
||||
VkSurfaceKHR GetSurface() { return Surface; };
|
||||
|
||||
void SetFramebufferResized(bool bResized) { bFramebufferResized = bResized; }
|
||||
|
||||
private:
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
|
||||
VulkanInstanceManager InstanceManager;
|
||||
VulkanDebugManager DebugManager;
|
||||
VulkanDeviceManager DeviceManager;
|
||||
VulkanSwapChain SwapChain;
|
||||
VulkanPipeline GraphicsPipeline;
|
||||
VulkanRenderPass RenderPass;
|
||||
VulkanFramebuffers Framebuffers;
|
||||
VulkanVertexBuffer VertexBuffer;
|
||||
VulkanCommandBuffers CommandBuffers;
|
||||
|
||||
// VkDevice Device;
|
||||
// VkPhysicalDevice PhysicalDevice;
|
||||
// VkQueue GraphicsQueue;
|
||||
|
||||
std::vector<VkSemaphore> ImageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> RenderFinishedSemaphores;
|
||||
std::vector<VkFence> InFlightFences;
|
||||
|
||||
bool bFramebufferResized = false;
|
||||
|
||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
uint32_t CurrentFrame = 0;
|
||||
};
|
||||
14
src/VulkanDebugManager.h → src/public/VulkanDebugManager.h
Normal file → Executable file
14
src/VulkanDebugManager.h → src/public/VulkanDebugManager.h
Normal file → Executable file
@@ -3,7 +3,7 @@
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
struct FCreateDebugUtilsMessengerExtParams
|
||||
struct FCreateParams
|
||||
{
|
||||
VkInstance Instance;
|
||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo;
|
||||
@@ -11,7 +11,7 @@ struct FCreateDebugUtilsMessengerExtParams
|
||||
VkDebugUtilsMessengerEXT* pDebugMessenger;
|
||||
};
|
||||
|
||||
struct FDestroyDebugUtilsMessengerExtParams
|
||||
struct FDestroyParams
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkDebugUtilsMessengerEXT DebugMessenger;
|
||||
@@ -24,12 +24,6 @@ public:
|
||||
VulkanDebugManager();
|
||||
~VulkanDebugManager();
|
||||
|
||||
VulkanDebugManager(const VulkanDebugManager&) = delete;
|
||||
VulkanDebugManager& operator=(const VulkanDebugManager&) = delete;
|
||||
|
||||
VulkanDebugManager(VulkanDebugManager&& Other) noexcept;
|
||||
VulkanDebugManager& operator=(VulkanDebugManager&& Other) noexcept;
|
||||
|
||||
void Initialize(VkInstance Instance);
|
||||
void Cleanup();
|
||||
|
||||
@@ -44,9 +38,9 @@ private:
|
||||
|
||||
VkDebugUtilsMessengerEXT DebugMessenger = VK_NULL_HANDLE;
|
||||
|
||||
VkResult CreateDebugUtilsMessengerExt(const FCreateDebugUtilsMessengerExtParams& Params);
|
||||
VkResult CreateDebugUtilsMessengerExt(const FCreateParams& Params);
|
||||
|
||||
void DestroyDebugUtilsMessengerExt(const FDestroyDebugUtilsMessengerExtParams& Params);
|
||||
void DestroyDebugUtilsMessengerExt(const FDestroyParams& Params);
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT MessageSeverity,
|
||||
86
src/public/VulkanDeviceManager.h
Executable file
86
src/public/VulkanDeviceManager.h
Executable file
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
struct FDeviceConfig
|
||||
{
|
||||
VkInstance Instance;
|
||||
bool bEnableValidationLayers;
|
||||
VkSurfaceKHR Surface;
|
||||
GLFWwindow* Window;
|
||||
};
|
||||
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
std::optional<uint32_t> GraphicsFamily;
|
||||
std::optional<uint32_t> PresentFamily;
|
||||
|
||||
bool IsComplete()
|
||||
{
|
||||
return GraphicsFamily.has_value() && PresentFamily.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct SwapChainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR Capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> Formats;
|
||||
std::vector<VkPresentModeKHR> PresentModes;
|
||||
};
|
||||
|
||||
class VulkanDeviceManager
|
||||
{
|
||||
public:
|
||||
VulkanDeviceManager();
|
||||
~VulkanDeviceManager();
|
||||
|
||||
void Initialize(FDeviceConfig InConfig);
|
||||
// VkInstance Instance,
|
||||
// bool EnableValidationLayers,
|
||||
// VkSurfaceKHR Surface,
|
||||
// GLFWwindow* Window);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void PickPhysicalDevice();
|
||||
void CreateLogicalDevice();
|
||||
|
||||
VkDevice GetDevice() { return Device; }
|
||||
VkPhysicalDevice GetPhysicalDevice() { return PhysicalDevice; }
|
||||
QueueFamilyIndices GetPhysicalQueueFamilies() { return PhysicalQueueFamilies; }
|
||||
VkQueue GetGraphicsQueue() { return GraphicsQueue; }
|
||||
VkQueue GetPresentQueue() { return PresentQueue; }
|
||||
SwapChainSupportDetails GetSwapChainSupport() { return SwapChainSupport; }
|
||||
|
||||
private:
|
||||
FDeviceConfig DeviceConfig;
|
||||
|
||||
// VkInstance Instance = VK_NULL_HANDLE;
|
||||
VkDevice Device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE;
|
||||
VkQueue GraphicsQueue = VK_NULL_HANDLE;
|
||||
VkQueue PresentQueue = VK_NULL_HANDLE;
|
||||
QueueFamilyIndices PhysicalQueueFamilies;
|
||||
// VkSurfaceKHR Surface;
|
||||
|
||||
// GLFWwindow* Window = nullptr;
|
||||
|
||||
SwapChainSupportDetails SwapChainSupport;
|
||||
|
||||
// bool bEnableValidationLayers = false;
|
||||
|
||||
bool IsDeviceSuitable(VkPhysicalDevice Device);
|
||||
|
||||
int RateDeviceSuitability(VkPhysicalDevice Device);
|
||||
|
||||
bool CheckDeviceExtensionSupport(VkPhysicalDevice Device);
|
||||
|
||||
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice Device);
|
||||
|
||||
SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device);
|
||||
};
|
||||
39
src/public/VulkanFramebuffers.h
Normal file
39
src/public/VulkanFramebuffers.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct FFramebufferConfig
|
||||
{
|
||||
VkDevice Device;
|
||||
VkRenderPass RenderPass;
|
||||
std::vector<VkImageView> SwapChainImageViews;
|
||||
VkExtent2D SwapChainExtent;
|
||||
};
|
||||
|
||||
class VulkanFramebuffers
|
||||
{
|
||||
public:
|
||||
void Initialize(FFramebufferConfig InConfig);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateFramebuffers();
|
||||
// void CreateFramebuffers(VkRenderPass RenderPass, std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent);
|
||||
|
||||
std::vector<VkFramebuffer> GetSwapChainFrameBuffers() { return SwapChainFramebuffers; }
|
||||
|
||||
// void CreateCommandPool(std::optional<uint32_t> GraphicsFamily);
|
||||
//
|
||||
// void CreateCommandBuffer();
|
||||
//
|
||||
// void RecordCommandBuffer(VkCommandBuffer CommandBuffer, uint32_t imageIndex, VkRenderPass RenderPass, VkExtent2D SwapChainExtent, VkPipeline GraphicsPipeline);
|
||||
|
||||
private:
|
||||
FFramebufferConfig FramebufferConfig;
|
||||
|
||||
std::vector<VkFramebuffer> SwapChainFramebuffers;
|
||||
};
|
||||
27
src/public/VulkanInstanceManager.h
Executable file
27
src/public/VulkanInstanceManager.h
Executable file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "VulkanDebugManager.h"
|
||||
|
||||
class VulkanInstanceManager
|
||||
{
|
||||
public:
|
||||
VulkanInstanceManager();
|
||||
~VulkanInstanceManager();
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateInstance(VulkanDebugManager* DebugManager = nullptr);
|
||||
const VkInstance GetInstance() const { return Instance; }
|
||||
|
||||
private:
|
||||
VkInstance Instance = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<const char*> GetRequiredExtensions(bool bEnableValidationLayers);
|
||||
|
||||
bool CheckValidationLayerSupport();
|
||||
};
|
||||
33
src/public/VulkanPipeline.h
Executable file
33
src/public/VulkanPipeline.h
Executable file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class VulkanPipeline
|
||||
{
|
||||
public:
|
||||
void Initialize(VkDevice InDevice);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
// void CreateRenderPass(VkFormat SwapChainImageFormat);
|
||||
|
||||
// void CreateFramebuffers(std::vector<VkImageView> SwapChainImageViews, VkExtent2D SwapChainExtent);
|
||||
|
||||
VkShaderModule CreateShaderModule(const std::vector<char>& Code);
|
||||
|
||||
void CreateGraphicsPipeline(VkExtent2D SwapChainExtent, VkRenderPass RenderPass);
|
||||
//
|
||||
// VkRenderPass GetRenderPass() { return RenderPass; }
|
||||
//
|
||||
VkPipeline GetGraphicsPipeline() { return GraphicsPipeline; }
|
||||
|
||||
private:
|
||||
VkDevice Device;
|
||||
// VkRenderPass RenderPass;
|
||||
VkPipelineLayout PipelineLayout;
|
||||
VkPipeline GraphicsPipeline;
|
||||
// std::vector<VkFramebuffer> SwapChainFrameBuffers;
|
||||
};
|
||||
20
src/public/VulkanRenderPass.h
Normal file
20
src/public/VulkanRenderPass.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
class VulkanRenderPass
|
||||
{
|
||||
public:
|
||||
void Initialize(VkDevice InDevice);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateRenderPass(VkFormat SwapChainImageFormat);
|
||||
|
||||
VkRenderPass GetRenderPass() { return RenderPass; }
|
||||
|
||||
private:
|
||||
VkDevice Device;
|
||||
VkRenderPass RenderPass;
|
||||
};
|
||||
93
src/public/VulkanSwapChain.h
Normal file
93
src/public/VulkanSwapChain.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
const std::vector<const char*> DeviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
//
|
||||
// struct SwapChainSupportDetails
|
||||
// {
|
||||
// VkSurfaceCapabilitiesKHR Capabilities;
|
||||
// std::vector<VkSurfaceFormatKHR> Formats;
|
||||
// std::vector<VkPresentModeKHR> PresentModes;
|
||||
// };
|
||||
|
||||
struct FSwapConfig
|
||||
{
|
||||
VkDevice Device;
|
||||
VkSurfaceKHR Surface;
|
||||
GLFWwindow* Window;
|
||||
std::optional<uint32_t> GraphicsFamily;
|
||||
std::optional<uint32_t> PresentFamily;
|
||||
VkSurfaceCapabilitiesKHR Capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> Formats;
|
||||
std::vector<VkPresentModeKHR> PresentModes;
|
||||
};
|
||||
|
||||
class VulkanSwapChain
|
||||
{
|
||||
public:
|
||||
VulkanSwapChain();
|
||||
~VulkanSwapChain();
|
||||
|
||||
void Initialize(FSwapConfig InConfig);
|
||||
|
||||
// void Initialize(
|
||||
// VkDevice InDevice,
|
||||
// VkSurfaceKHR InSurface,
|
||||
// GLFWwindow* InWindow);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateSwapChain();
|
||||
// void CreateSwapChain(
|
||||
// std::optional<uint32_t> GraphicsFamily,
|
||||
// std::optional<uint32_t> PresentFamily,
|
||||
// VkSurfaceCapabilitiesKHR Capabilities,
|
||||
// std::vector<VkSurfaceFormatKHR> Formats,
|
||||
// std::vector<VkPresentModeKHR> PresentModes);
|
||||
|
||||
void CreateImageViews();
|
||||
|
||||
// void RecreateSwapChain();
|
||||
|
||||
VkSwapchainKHR GetSwapChain() { return SwapChain; }
|
||||
VkFormat GetSwapChainImageFormat() { return SwapChainImageFormat; }
|
||||
VkExtent2D GetSwapChainExtent() { return SwapChainExtent; }
|
||||
std::vector<VkImageView> GetSwapChainImageViews() { return SwapChainImageViews; }
|
||||
|
||||
private:
|
||||
FSwapConfig SwapConfig;
|
||||
// VkPhysicalDevice PhysicalDevice;
|
||||
// VkDevice Device;
|
||||
// VkSurfaceKHR Surface;
|
||||
//
|
||||
// GLFWwindow* Window = nullptr;
|
||||
|
||||
std::vector<VkImage> SwapChainImages;
|
||||
VkSwapchainKHR SwapChain = VK_NULL_HANDLE;
|
||||
VkFormat SwapChainImageFormat;
|
||||
VkExtent2D SwapChainExtent;
|
||||
|
||||
std::vector<VkImageView> SwapChainImageViews;
|
||||
|
||||
// bool IsDeviceSuitable(VkPhysicalDevice Device);
|
||||
//
|
||||
// int RateDeviceSuitability(VkPhysicalDevice Device);
|
||||
//
|
||||
// bool CheckDeviceExtensionSupport(VkPhysicalDevice Device);
|
||||
|
||||
// SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice Device);
|
||||
|
||||
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& AvailableFormats);
|
||||
|
||||
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& AvailablePresentModes);
|
||||
|
||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& Capabilities);
|
||||
};
|
||||
35
src/public/VulkanVertexBuffer.h
Normal file
35
src/public/VulkanVertexBuffer.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "Primitives.h"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
struct FVertexBufferConfig
|
||||
{
|
||||
VkDevice Device;
|
||||
VkPhysicalDevice PhysicalDevice;
|
||||
};
|
||||
|
||||
class VulkanVertexBuffer
|
||||
{
|
||||
public:
|
||||
void Initialize(FVertexBufferConfig InConfig);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void CreateVertexBuffer(std::vector<Vertex> InVertices);
|
||||
|
||||
uint32_t FindMemoryType(uint32_t TypeFilter, VkMemoryPropertyFlags Properties);
|
||||
|
||||
VkBuffer GetVertexBuffer() { return VertexBuffer; }
|
||||
|
||||
private:
|
||||
FVertexBufferConfig Config;
|
||||
VkBuffer VertexBuffer;
|
||||
VkDeviceMemory VertexBufferMemory;
|
||||
};
|
||||
52
include/FileReader.h → src/utilities/FileReader.h
Normal file → Executable file
52
include/FileReader.h → src/utilities/FileReader.h
Normal file → Executable file
@@ -1,26 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
static std::vector<char> ReadFile(const std::string& FileName)
|
||||
{
|
||||
std::ifstream File(FileName, std::ios::ate | std::ios::binary);
|
||||
|
||||
if (!File.is_open())
|
||||
{
|
||||
Log::Error("Failed to open file: " + FileName);
|
||||
}
|
||||
|
||||
size_t FileSize = (size_t)File.tellg();
|
||||
std::vector<char> Buffer(FileSize);
|
||||
|
||||
File.seekg(0);
|
||||
File.read(Buffer.data(), FileSize);
|
||||
|
||||
File.close();
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "utilities/Logger.h"
|
||||
|
||||
static std::vector<char> ReadFile(const std::string& FileName)
|
||||
{
|
||||
std::ifstream File(FileName, std::ios::ate | std::ios::binary);
|
||||
|
||||
if (!File.is_open())
|
||||
{
|
||||
Log::Error("Failed to open file: " + FileName);
|
||||
}
|
||||
|
||||
size_t FileSize = (size_t)File.tellg();
|
||||
std::vector<char> Buffer(FileSize);
|
||||
|
||||
File.seekg(0);
|
||||
File.read(Buffer.data(), FileSize);
|
||||
|
||||
File.close();
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
4
include/Logger.cpp → src/utilities/Logger.cpp
Normal file → Executable file
4
include/Logger.cpp → src/utilities/Logger.cpp
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
#include "Logger.h"
|
||||
#include "utilities/Logger.h"
|
||||
#include <iostream>
|
||||
|
||||
void Log::Message(Level Level, const std::string& Message, const std::source_location& Location)
|
||||
@@ -61,4 +61,4 @@ void Log::Message(Level Level, const std::string& Message, const std::source_loc
|
||||
{
|
||||
throw std::runtime_error(LogMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
0
include/Logger.h → src/utilities/Logger.h
Normal file → Executable file
0
include/Logger.h → src/utilities/Logger.h
Normal file → Executable file
Reference in New Issue
Block a user