Add Buffer abstractions
This commit is contained in:
+11
-2
@@ -114,7 +114,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);GLM_FORCE_LEFT_HANDED;GLFW_INCLUDE_VULKAN;GLM_FORCE_RADIANS;GLM_FORCE_DEPTH_ZERO_TO_ONE</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)ext/include/;C:/VulkanSDK/1.3.236.0/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)ext/include/;C:/VulkanSDK/1.3.236.0/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);GLM_FORCE_LEFT_HANDED;GLFW_INCLUDE_VULKAN;GLM_FORCE_RADIANS;GLM_FORCE_DEPTH_ZERO_TO_ONE</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)ext/include/;C:/VulkanSDK/1.3.236.0/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)ext/include/;C:/VulkanSDK/1.3.236.0/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
@@ -148,15 +148,24 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
|
<ClCompile Include="src\SwapChain.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\Buffer.h" />
|
<ClInclude Include="src\Buffer.h" />
|
||||||
<ClInclude Include="src\Common.h" />
|
<ClInclude Include="src\Common.h" />
|
||||||
<ClInclude Include="src\DebugMessenger.h" />
|
<ClInclude Include="src\DebugMessenger.h" />
|
||||||
<ClInclude Include="src\FileSystem.h" />
|
<ClInclude Include="src\FileSystem.h" />
|
||||||
|
<ClInclude Include="src\IndexBuffer.h" />
|
||||||
|
<ClInclude Include="src\Pipeline.h" />
|
||||||
|
<ClInclude Include="src\PipelineCreator.h" />
|
||||||
|
<ClInclude Include="src\UniformBuffer.h" />
|
||||||
<ClInclude Include="src\Instance.h" />
|
<ClInclude Include="src\Instance.h" />
|
||||||
<ClInclude Include="src\QueueFamilies.h" />
|
<ClInclude Include="src\QueueFamilies.h" />
|
||||||
<ClInclude Include="src\SwapChain.h" />
|
<ClInclude Include="src\SwapChain.h" />
|
||||||
|
<ClInclude Include="src\Timer.h" />
|
||||||
|
<ClInclude Include="src\Vertex.h" />
|
||||||
|
<ClInclude Include="src\VertexBuffer.h" />
|
||||||
|
<ClInclude Include="src\VertexDescriptor.h" />
|
||||||
<ClInclude Include="src\VulkanException.h" />
|
<ClInclude Include="src\VulkanException.h" />
|
||||||
<ClInclude Include="src\Window.h" />
|
<ClInclude Include="src\Window.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
<ClCompile Include="src\main.cpp">
|
<ClCompile Include="src\main.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\SwapChain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\DebugMessenger.h">
|
<ClInclude Include="src\DebugMessenger.h">
|
||||||
@@ -47,6 +50,30 @@
|
|||||||
<ClInclude Include="src\Window.h">
|
<ClInclude Include="src\Window.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Timer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\UniformBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Pipeline.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\PipelineCreator.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Vertex.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\IndexBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\VertexBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\VertexDescriptor.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="res\shaders\shader.frag" />
|
<None Include="res\shaders\shader.frag" />
|
||||||
|
|||||||
+46
-22
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
class Buffer
|
class Buffer
|
||||||
{
|
{
|
||||||
private:
|
CP_DELETE_COPY_AND_MOVE_CTOR(Buffer);
|
||||||
|
protected:
|
||||||
Instance& instance;
|
Instance& instance;
|
||||||
|
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
@@ -27,7 +28,7 @@ public:
|
|||||||
createInfo.usage = usage;
|
createInfo.usage = usage;
|
||||||
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer");
|
CP_VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer");
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements;
|
VkMemoryRequirements memoryRequirements;
|
||||||
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements);
|
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements);
|
||||||
@@ -37,12 +38,12 @@ public:
|
|||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
allocateInfo.memoryTypeIndex = FindMemoryType(instance, memoryRequirements.memoryTypeBits, properties);
|
allocateInfo.memoryTypeIndex = FindMemoryType(instance, memoryRequirements.memoryTypeBits, properties);
|
||||||
|
|
||||||
VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Failed to allocate buffer memory");
|
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Failed to allocate buffer memory");
|
||||||
|
|
||||||
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
|
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Buffer()
|
virtual ~Buffer()
|
||||||
{
|
{
|
||||||
vkFreeMemory(instance.GetDevice(), memory, nullptr);
|
vkFreeMemory(instance.GetDevice(), memory, nullptr);
|
||||||
vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
|
vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
|
||||||
@@ -50,7 +51,7 @@ public:
|
|||||||
|
|
||||||
void Update(void* indexData, int index)
|
void Update(void* indexData, int index)
|
||||||
{
|
{
|
||||||
ASSERT(index >= 0 && index < count, "instance is outside of the buffer");
|
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
|
||||||
|
|
||||||
if (mappedData == nullptr)
|
if (mappedData == nullptr)
|
||||||
{
|
{
|
||||||
@@ -65,34 +66,58 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateStaging(void* data)
|
||||||
|
{
|
||||||
|
VkDeviceSize bufferSize = size * count;
|
||||||
|
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
||||||
|
|
||||||
|
stagingBuffer.Update(data, 0);
|
||||||
|
|
||||||
|
CopyBuffer(instance, stagingBuffer, *this, 0, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateStaging(void* data, VkDeviceSize offset, VkDeviceSize size)
|
||||||
|
{
|
||||||
|
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, 1};
|
||||||
|
|
||||||
|
stagingBuffer.Update(data, 0);
|
||||||
|
|
||||||
|
CopyBuffer(instance, stagingBuffer, *this, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
void Map()
|
void Map()
|
||||||
{
|
{
|
||||||
ASSERT(mappedData == nullptr, "Mapping an already mapped buffer")
|
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
|
||||||
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unmap()
|
void Unmap()
|
||||||
{
|
{
|
||||||
ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer")
|
CP_ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer");
|
||||||
|
|
||||||
vkUnmapMemory(instance.GetDevice(), memory);
|
vkUnmapMemory(instance.GetDevice(), memory);
|
||||||
mappedData = nullptr;
|
mappedData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Bind(VkCommandBuffer commandBuffer) { CP_UNIMPLEMENTED(); };
|
||||||
|
|
||||||
|
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &handle, &offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindAsIndexBuffer(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
// TODO: Maybe don't assume that indices are uint16?
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
}
|
||||||
|
|
||||||
VkBuffer GetHandle() const
|
VkBuffer GetHandle() const
|
||||||
{
|
{
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorBufferInfo GetDescriptorBufferInfo(int instance)
|
|
||||||
{
|
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
|
||||||
bufferInfo.buffer = handle;
|
|
||||||
bufferInfo.offset = (VkDeviceSize)instance * size;
|
|
||||||
bufferInfo.range = size;
|
|
||||||
return bufferInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize GetSize() const
|
VkDeviceSize GetSize() const
|
||||||
{
|
{
|
||||||
return size;
|
return size;
|
||||||
@@ -100,13 +125,12 @@ public:
|
|||||||
|
|
||||||
VkDeviceSize GetPosition(int index) const
|
VkDeviceSize GetPosition(int index) const
|
||||||
{
|
{
|
||||||
ASSERT(index >= 0 && index < count, "Instance is outside of the buffer");
|
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
|
||||||
return size * (VkDeviceSize)index;
|
return size * (VkDeviceSize)index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer)
|
static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer, VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
ASSERT(srcBuffer.size == dstBuffer.size && srcBuffer.count == dstBuffer.count, "Buffers have different sizes");
|
|
||||||
VkCommandBufferAllocateInfo allocateInfo{};
|
VkCommandBufferAllocateInfo allocateInfo{};
|
||||||
|
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
@@ -115,7 +139,7 @@ public:
|
|||||||
allocateInfo.commandBufferCount = 1;
|
allocateInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer;
|
VkCommandBuffer commandBuffer;
|
||||||
VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer");
|
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer");
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
@@ -124,9 +148,9 @@ public:
|
|||||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||||
|
|
||||||
VkBufferCopy bufferCopy{};
|
VkBufferCopy bufferCopy{};
|
||||||
bufferCopy.dstOffset = 0;
|
bufferCopy.dstOffset = offset;
|
||||||
bufferCopy.srcOffset = 0;
|
bufferCopy.srcOffset = 0;
|
||||||
bufferCopy.size = srcBuffer.size * (VkDeviceSize)srcBuffer.count;
|
bufferCopy.size = size;
|
||||||
|
|
||||||
vkCmdCopyBuffer(commandBuffer, srcBuffer.GetHandle(), dstBuffer.GetHandle(), 1, &bufferCopy);
|
vkCmdCopyBuffer(commandBuffer, srcBuffer.GetHandle(), dstBuffer.GetHandle(), 1, &bufferCopy);
|
||||||
|
|
||||||
|
|||||||
+26
-4
@@ -4,10 +4,21 @@
|
|||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define ASSERT(Function, message) if(!(Function)) { throw std::runtime_error(message); } while(false)
|
#define CP_DEBUG(format, ...) std::cout << "[DBG] " << StringFormat(format, __VA_ARGS__) << std::endl
|
||||||
#define VK_ASSERT(Function, message) if(Function != VK_SUCCESS) { throw VulkanException(message); } while(false)
|
#define CP_INFO(format, ...) std::cout << "[INF] " << StringFormat(format, __VA_ARGS__) << std::endl
|
||||||
|
#define CP_WARN(format, ...) std::cout << "[WRN] " << StringFormat(format, __VA_ARGS__) << std::endl
|
||||||
|
#define CP_ERR(format, ...) std::cout << "[ERR] " << StringFormat(format, __VA_ARGS__) << std::endl
|
||||||
|
|
||||||
VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
|
||||||
|
#define CP_ASSERT(Function, format, ...) if(!(Function)) { throw std::runtime_error(StringFormat(format, __VA_ARGS__)); } while(false)
|
||||||
|
#define CP_VK_ASSERT(Function, format, ...) if(Function != VK_SUCCESS) { throw VulkanException(StringFormat(format, __VA_ARGS__)); } while(false)
|
||||||
|
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
||||||
|
ClassName(ClassName&&) = delete; \
|
||||||
|
ClassName(const ClassName&) = delete; \
|
||||||
|
ClassName& operator=(ClassName&&) = delete; \
|
||||||
|
ClassName& operator=(const ClassName&) = delete
|
||||||
|
|
||||||
|
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator,
|
const VkAllocationCallbacks* pAllocator,
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
||||||
@@ -18,7 +29,7 @@ VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
|||||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
VkDebugUtilsMessengerEXT debugMessenger,
|
VkDebugUtilsMessengerEXT debugMessenger,
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
@@ -26,3 +37,14 @@ void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
|||||||
func(instance, debugMessenger, pAllocator);
|
func(instance, debugMessenger, pAllocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
std::string StringFormat(const std::string& format, Args... args)
|
||||||
|
{
|
||||||
|
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
||||||
|
CP_ASSERT(size > 0, "Error during formatting");
|
||||||
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
|
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||||
|
return std::string(buf.get(), buf.get() + size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
class DebugMessenger
|
class DebugMessenger
|
||||||
{
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
|
||||||
public:
|
public:
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
VkDebugUtilsMessengerEXT debugMessenger;
|
VkDebugUtilsMessengerEXT debugMessenger;
|
||||||
@@ -22,7 +23,7 @@ public:
|
|||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
createInfo.pfnUserCallback = DebugCallback;
|
createInfo.pfnUserCallback = DebugCallback;
|
||||||
createInfo.pUserData = nullptr;
|
createInfo.pUserData = nullptr;
|
||||||
VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "Failed to initialze debug messenger");
|
CP_VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "Failed to initialze debug messenger");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,11 +34,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugMessenger(DebugMessenger&&) = delete;
|
|
||||||
DebugMessenger(const DebugMessenger&) = delete;
|
|
||||||
DebugMessenger& operator=(DebugMessenger&&) = delete;
|
|
||||||
DebugMessenger& operator=(const DebugMessenger&) = delete;
|
|
||||||
|
|
||||||
static void AddRequiredExtensions(std::vector<const char*>* extensions)
|
static void AddRequiredExtensions(std::vector<const char*>* extensions)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace FileSystem
|
|||||||
static std::vector<char> ReadFile(const std::string& filename)
|
static std::vector<char> ReadFile(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||||
ASSERT(file.is_open(), "Failed to open file");
|
CP_ASSERT(file.is_open(), "Failed to open file");
|
||||||
|
|
||||||
size_t fileSize = (size_t) file.tellg();
|
size_t fileSize = (size_t) file.tellg();
|
||||||
std::vector<char> buffer(fileSize);
|
std::vector<char> buffer(fileSize);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
|
|
||||||
|
class IndexBuffer : public Buffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(IndexBuffer);
|
||||||
|
private:
|
||||||
|
int indexCount;
|
||||||
|
public:
|
||||||
|
IndexBuffer(Instance& instance, int indexCount)
|
||||||
|
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Bind(VkCommandBuffer commandBuffer) override
|
||||||
|
{
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
+103
-29
@@ -1,35 +1,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "DebugMessenger.h"
|
#include "DebugMessenger.h"
|
||||||
#include "QueueFamilies.h"
|
#include "QueueFamilies.h"
|
||||||
#include "SwapChain.h"
|
#include "SwapChain.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
class Instance final
|
class Instance final
|
||||||
{
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Instance);
|
||||||
private:
|
private:
|
||||||
static const int MAX_FRAMES_IN_FLIGHT = 2;
|
static const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
static const int WINDOW_WIDTH = 1920;
|
static const int WINDOW_WIDTH = 1920;
|
||||||
static const int WINDOW_HEIGHT = 1080;
|
static const int WINDOW_HEIGHT = 1080;
|
||||||
|
|
||||||
|
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
std::unique_ptr<DebugMessenger> debugMessenger;
|
std::unique_ptr<DebugMessenger> debugMessenger;
|
||||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
|
uint32_t graphicsQueueIndex;
|
||||||
|
uint32_t presentQueueIndex;
|
||||||
VkQueue graphicsQueue;
|
VkQueue graphicsQueue;
|
||||||
VkQueue presentQueue;
|
VkQueue presentQueue;
|
||||||
std::unique_ptr<SwapChain> swapChain;
|
std::unique_ptr<SwapChain> swapChain;
|
||||||
|
int flightIndex;
|
||||||
|
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||||
|
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||||
|
std::vector<VkFence> inFlightFences;
|
||||||
VkCommandPool commandPool;
|
VkCommandPool commandPool;
|
||||||
bool framebufferResized = false;
|
bool framebufferResized = false;
|
||||||
|
|
||||||
|
int frameCount = 0;
|
||||||
|
Timer timer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Instance(const std::string& applicationName)
|
Instance(const std::string& applicationName)
|
||||||
{
|
{
|
||||||
|
timer.Start();
|
||||||
InitializeWindow(applicationName);
|
InitializeWindow(applicationName);
|
||||||
InitializeInstance(applicationName);
|
InitializeInstance(applicationName);
|
||||||
InitializeDebugMessenger();
|
InitializeDebugMessenger();
|
||||||
@@ -38,10 +50,18 @@ public:
|
|||||||
InitializeLogicalDevice();
|
InitializeLogicalDevice();
|
||||||
InitializeSwapChain();
|
InitializeSwapChain();
|
||||||
InitializeCommandPool();
|
InitializeCommandPool();
|
||||||
|
InitializeSyncObjects();
|
||||||
|
std::cout << "Initialized Vulkan in " << timer.Elapsed() << " seconds" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Instance()
|
~Instance()
|
||||||
{
|
{
|
||||||
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||||
|
{
|
||||||
|
vkDestroyFence(device, inFlightFences[i], nullptr);
|
||||||
|
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
|
||||||
|
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
|
||||||
|
}
|
||||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
swapChain.reset();
|
swapChain.reset();
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
@@ -53,32 +73,38 @@ public:
|
|||||||
|
|
||||||
bool BeginPresent()
|
bool BeginPresent()
|
||||||
{
|
{
|
||||||
if (!swapChain->BeginPresent())
|
vkWaitForFences(device, 1, &inFlightFences[flightIndex], VK_TRUE, UINT64_MAX);
|
||||||
return true;
|
|
||||||
|
if (!swapChain->BeginPresent(imageAvailableSemaphores[flightIndex]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vkResetFences(device, 1, &inFlightFences[flightIndex]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EndPresent()
|
bool EndPresent()
|
||||||
{
|
{
|
||||||
swapChain->EndPresent(presentQueue, framebufferResized);
|
swapChain->EndPresent(presentQueue, &renderFinishedSemaphores[flightIndex], framebufferResized);
|
||||||
|
|
||||||
|
framebufferResized = false;
|
||||||
|
flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||||
return !glfwWindowShouldClose(window);
|
return !glfwWindowShouldClose(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers)
|
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers)
|
||||||
{
|
{
|
||||||
VkSemaphore waitSemaphores[] = {swapChain->GetAvailableImageSemaphore()};
|
|
||||||
VkSemaphore signalSemaphores[] = {swapChain->GetRenderFinishedSemaphore()};
|
|
||||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||||
VkSubmitInfo submitInfo{};
|
VkSubmitInfo submitInfo{};
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
submitInfo.pWaitSemaphores = &imageAvailableSemaphores[flightIndex];
|
||||||
submitInfo.pWaitDstStageMask = waitStages;
|
submitInfo.pWaitDstStageMask = waitStages;
|
||||||
submitInfo.commandBufferCount = commandBuffers.size();
|
submitInfo.commandBufferCount = commandBuffers.size();
|
||||||
submitInfo.pCommandBuffers = commandBuffers.data();
|
submitInfo.pCommandBuffers = commandBuffers.data();
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
submitInfo.pSignalSemaphores = &renderFinishedSemaphores[flightIndex];
|
||||||
|
|
||||||
VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, swapChain->GetInFlightFence()), "Failed to submit command buffer");
|
CP_VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[flightIndex]), "Failed to submit command buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
VkInstance GetInstance() const
|
VkInstance GetInstance() const
|
||||||
@@ -86,6 +112,16 @@ public:
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWwindow* GetWindow() const
|
||||||
|
{
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceKHR GetSurface() const
|
||||||
|
{
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
VkPhysicalDevice GetPhysicalDevice() const
|
VkPhysicalDevice GetPhysicalDevice() const
|
||||||
{
|
{
|
||||||
return physicalDevice;
|
return physicalDevice;
|
||||||
@@ -106,7 +142,12 @@ public:
|
|||||||
return graphicsQueue;
|
return graphicsQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetMaxFramesInFlight()
|
int GetFlightIndex() const
|
||||||
|
{
|
||||||
|
return flightIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetMaxFramesInFlight() const
|
||||||
{
|
{
|
||||||
return MAX_FRAMES_IN_FLIGHT;
|
return MAX_FRAMES_IN_FLIGHT;
|
||||||
}
|
}
|
||||||
@@ -120,7 +161,21 @@ private:
|
|||||||
void InitializeWindow(const std::string& applicationName)
|
void InitializeWindow(const std::string& applicationName)
|
||||||
{
|
{
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(FULLSCREEN)
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||||
|
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), glfwGetPrimaryMonitor(), nullptr);
|
||||||
|
#elif defined(BORDERLESS_WINDOWED)
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||||
|
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), nullptr, nullptr);
|
||||||
|
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||||
|
#else
|
||||||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
|
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
|
||||||
|
#endif
|
||||||
|
CP_ASSERT(window, "Failed to initialize glfw window");
|
||||||
|
|
||||||
glfwSetWindowUserPointer(window, this);
|
glfwSetWindowUserPointer(window, this);
|
||||||
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
|
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
|
||||||
@@ -132,7 +187,7 @@ private:
|
|||||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
appInfo.pApplicationName = applicationName.c_str();
|
appInfo.pApplicationName = applicationName.c_str();
|
||||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||||
appInfo.pEngineName = "Greet Engine";
|
appInfo.pEngineName = "Copium Engine";
|
||||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||||
appInfo.apiVersion = VK_API_VERSION_1_1;
|
appInfo.apiVersion = VK_API_VERSION_1_1;
|
||||||
|
|
||||||
@@ -151,7 +206,7 @@ private:
|
|||||||
|
|
||||||
std::vector<const char*> layers{};
|
std::vector<const char*> layers{};
|
||||||
DebugMessenger::AddRequiredLayers(&layers);
|
DebugMessenger::AddRequiredLayers(&layers);
|
||||||
ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
|
CP_ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
|
||||||
|
|
||||||
VkInstanceCreateInfo createInfo{};
|
VkInstanceCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
@@ -160,7 +215,7 @@ private:
|
|||||||
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
|
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
|
||||||
createInfo.enabledLayerCount = layers.size();
|
createInfo.enabledLayerCount = layers.size();
|
||||||
createInfo.ppEnabledLayerNames = layers.data();
|
createInfo.ppEnabledLayerNames = layers.data();
|
||||||
VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
|
CP_VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeDebugMessenger()
|
void InitializeDebugMessenger()
|
||||||
@@ -170,14 +225,14 @@ private:
|
|||||||
|
|
||||||
void InitializeSurface()
|
void InitializeSurface()
|
||||||
{
|
{
|
||||||
VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
|
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectPhysicalDevice()
|
void SelectPhysicalDevice()
|
||||||
{
|
{
|
||||||
uint32_t deviceCount;
|
uint32_t deviceCount;
|
||||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||||
ASSERT(deviceCount != 0, "No available devices support Vulkan");
|
CP_ASSERT(deviceCount != 0, "No available devices support Vulkan");
|
||||||
|
|
||||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||||
@@ -199,17 +254,17 @@ private:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
|
CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeLogicalDevice()
|
void InitializeLogicalDevice()
|
||||||
{
|
{
|
||||||
QueueFamilies queueFamilies{surface, physicalDevice};
|
QueueFamiliesQuery query{surface, physicalDevice};
|
||||||
|
|
||||||
float queuePriority = 1.0f;
|
float queuePriority = 1.0f;
|
||||||
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
|
||||||
std::set<uint32_t> uniqueQueueFamilies{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
|
std::set<uint32_t> uniqueQueueFamilies{query.graphicsFamily.value(), query.presentFamily.value()};
|
||||||
for(auto&& queueFamily : uniqueQueueFamilies)
|
for(auto&& queueFamily : uniqueQueueFamilies)
|
||||||
{
|
{
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||||
@@ -230,28 +285,48 @@ private:
|
|||||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||||
createInfo.enabledExtensionCount = deviceExtensions.size();
|
createInfo.enabledExtensionCount = deviceExtensions.size();
|
||||||
|
|
||||||
VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
|
CP_VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
|
||||||
|
|
||||||
vkGetDeviceQueue(device, queueFamilies.graphicsFamily.value(), 0, &graphicsQueue);
|
graphicsQueueIndex = query.graphicsFamily.value();
|
||||||
vkGetDeviceQueue(device, queueFamilies.presentFamily.value(), 0, &presentQueue);
|
presentQueueIndex = query.presentFamily.value();
|
||||||
|
vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
|
||||||
|
vkGetDeviceQueue(device, presentQueueIndex , 0, &presentQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeSwapChain()
|
void InitializeSwapChain()
|
||||||
{
|
{
|
||||||
swapChain = std::make_unique<SwapChain>(window, surface, device, physicalDevice);
|
swapChain = std::make_unique<SwapChain>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeCommandPool()
|
void InitializeCommandPool()
|
||||||
{
|
{
|
||||||
QueueFamilies queueFamilies{surface, physicalDevice};
|
|
||||||
|
|
||||||
VkCommandPoolCreateInfo createInfo{};
|
VkCommandPoolCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
createInfo.queueFamilyIndex = queueFamilies.graphicsFamily.value();
|
createInfo.queueFamilyIndex = graphicsQueueIndex;
|
||||||
VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
|
CP_VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitializeSyncObjects()
|
||||||
|
{
|
||||||
|
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
VkSemaphoreCreateInfo semaphoreCreateInfo{};
|
||||||
|
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||||
|
{
|
||||||
|
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
|
||||||
|
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
|
||||||
|
|
||||||
|
VkFenceCreateInfo fenceCreateInfo{};
|
||||||
|
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const char*> GetRequiredExtensions()
|
std::vector<const char*> GetRequiredExtensions()
|
||||||
{
|
{
|
||||||
uint32_t glfwExtensionCount;
|
uint32_t glfwExtensionCount;
|
||||||
@@ -308,8 +383,8 @@ private:
|
|||||||
if (!deviceFeatures.fillModeNonSolid)
|
if (!deviceFeatures.fillModeNonSolid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QueueFamilies queueFamilies{surface, device};
|
QueueFamiliesQuery query{surface, device};
|
||||||
if (!queueFamilies.AllRequiredFamiliesSupported())
|
if (!query.AllRequiredFamiliesSupported())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CheckDeviceExtensionSupport(device))
|
if (!CheckDeviceExtensionSupport(device))
|
||||||
@@ -355,5 +430,4 @@ private:
|
|||||||
Instance* instance = static_cast<Instance*>(glfwGetWindowUserPointer(window));
|
Instance* instance = static_cast<Instance*>(glfwGetWindowUserPointer(window));
|
||||||
instance->framebufferResized = true;
|
instance->framebufferResized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "PipelineCreator.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
|
class Pipeline
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Pipeline);
|
||||||
|
private:
|
||||||
|
Instance& instance;
|
||||||
|
|
||||||
|
std::map<uint32_t, VkDescriptorSetLayout> vertexDescriptorSetLayouts;
|
||||||
|
std::map<uint32_t, VkDescriptorSetLayout> fragmentDescriptorSetLayouts;
|
||||||
|
VkPipelineLayout pipelineLayout;
|
||||||
|
VkPipeline graphicsPipeline;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Pipeline(Instance& instance, PipelineCreator creator)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
InitializeDescriptorSetLayouts(creator);
|
||||||
|
InitializePipeline(creator);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pipeline()
|
||||||
|
{
|
||||||
|
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
|
||||||
|
for (auto&& descriptorSetLayout : vertexDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout.second, nullptr);
|
||||||
|
}
|
||||||
|
for (auto&& descriptorSetLayout : fragmentDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout.second, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bind(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
||||||
|
|
||||||
|
VkViewport viewport{};
|
||||||
|
viewport.x = 0.0f;
|
||||||
|
viewport.y = 0.0f;
|
||||||
|
viewport.width = instance.GetSwapChain().GetExtent().width;
|
||||||
|
viewport.height = instance.GetSwapChain().GetExtent().height;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
VkRect2D scissor{};
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = instance.GetSwapChain().GetExtent();
|
||||||
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineLayout GetPipelineLayout() const
|
||||||
|
{
|
||||||
|
return pipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayout GetVertexDescriptorSetLayout(uint32_t binding)
|
||||||
|
{
|
||||||
|
return vertexDescriptorSetLayouts.at(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayout GetFragmentDescriptorSetLayout(uint32_t binding)
|
||||||
|
{
|
||||||
|
return fragmentDescriptorSetLayouts.at(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeDescriptorSetLayouts(const PipelineCreator& creator)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (auto& binding : creator.vertexDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
vertexDescriptorSetLayouts.emplace(binding, InitializeDescriptorSetLayout(binding, VK_SHADER_STAGE_VERTEX_BIT));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (auto& binding : creator.fragmentDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
fragmentDescriptorSetLayouts.emplace(binding, InitializeDescriptorSetLayout(binding, VK_SHADER_STAGE_FRAGMENT_BIT));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializePipeline(const PipelineCreator& creator)
|
||||||
|
{
|
||||||
|
std::vector<char> vertShaderCode = FileSystem::ReadFile(creator.vertexShader);
|
||||||
|
std::vector<char> fragShaderCode = FileSystem::ReadFile(creator.fragmentShader);
|
||||||
|
|
||||||
|
VkShaderModule vertShaderModule = InitializeShaderModule(vertShaderCode);
|
||||||
|
VkShaderModule fragShaderModule = InitializeShaderModule(fragShaderCode);
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo shaderStages[2];
|
||||||
|
shaderStages[0] = {};
|
||||||
|
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
shaderStages[0].module = vertShaderModule;
|
||||||
|
shaderStages[0].pName = "main";
|
||||||
|
|
||||||
|
shaderStages[1] = {};
|
||||||
|
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
shaderStages[1].module = fragShaderModule;
|
||||||
|
shaderStages[1].pName = "main";
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
|
||||||
|
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertexInputCreateInfo.vertexBindingDescriptionCount = 1;
|
||||||
|
vertexInputCreateInfo.pVertexBindingDescriptions = &creator.vertexInputBindingDescription;
|
||||||
|
vertexInputCreateInfo.vertexAttributeDescriptionCount = creator.vertexInputAttributeDescriptions.size();
|
||||||
|
vertexInputCreateInfo.pVertexAttributeDescriptions = creator.vertexInputAttributeDescriptions.data();
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
|
||||||
|
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
inputAssemblyCreateInfo.topology = creator.topology;
|
||||||
|
inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkViewport viewport{};
|
||||||
|
viewport.x = 0;
|
||||||
|
viewport.y = 0;
|
||||||
|
viewport.width = instance.GetSwapChain().GetExtent().width;
|
||||||
|
viewport.height = instance.GetSwapChain().GetExtent().height;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
VkRect2D scissor{};
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = instance.GetSwapChain().GetExtent();
|
||||||
|
|
||||||
|
std::vector<VkDynamicState> dynamicStates = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{};
|
||||||
|
dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamicStateCreateInfo.dynamicStateCount = dynamicStates.size();
|
||||||
|
dynamicStateCreateInfo.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewportStateCreateInfo{};
|
||||||
|
viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewportStateCreateInfo.viewportCount = 1;
|
||||||
|
viewportStateCreateInfo.pViewports = &viewport;
|
||||||
|
viewportStateCreateInfo.scissorCount = 1;
|
||||||
|
viewportStateCreateInfo.pScissors = &scissor;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterizerCreateInfo{};
|
||||||
|
rasterizerCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterizerCreateInfo.depthClampEnable = VK_FALSE;
|
||||||
|
rasterizerCreateInfo.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rasterizerCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterizerCreateInfo.lineWidth = 1.0f;
|
||||||
|
rasterizerCreateInfo.cullMode = creator.cullMode;
|
||||||
|
rasterizerCreateInfo.frontFace = creator.frontFace;
|
||||||
|
|
||||||
|
rasterizerCreateInfo.depthBiasEnable = VK_FALSE;
|
||||||
|
rasterizerCreateInfo.depthBiasConstantFactor = 0.0f;
|
||||||
|
rasterizerCreateInfo.depthBiasClamp = 0.0f;
|
||||||
|
rasterizerCreateInfo.depthBiasSlopeFactor = 0.0f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampleCreateInfo{};
|
||||||
|
multisampleCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisampleCreateInfo.sampleShadingEnable = VK_FALSE;
|
||||||
|
multisampleCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
multisampleCreateInfo.minSampleShading = 1.0f;
|
||||||
|
multisampleCreateInfo.pSampleMask = nullptr;
|
||||||
|
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
|
||||||
|
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState colorBlendAttachment{}; // TODO: Add to PipelineCreator
|
||||||
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||||
|
VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT |
|
||||||
|
VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||||
|
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo{};
|
||||||
|
colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
colorBlendCreateInfo.logicOpEnable = VK_FALSE;
|
||||||
|
colorBlendCreateInfo.logicOp = VK_LOGIC_OP_COPY;
|
||||||
|
colorBlendCreateInfo.attachmentCount = 1;
|
||||||
|
colorBlendCreateInfo.pAttachments = &colorBlendAttachment;
|
||||||
|
colorBlendCreateInfo.blendConstants[0] = 0.0f;
|
||||||
|
colorBlendCreateInfo.blendConstants[1] = 0.0f;
|
||||||
|
colorBlendCreateInfo.blendConstants[2] = 0.0f;
|
||||||
|
colorBlendCreateInfo.blendConstants[3] = 0.0f;
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayout> layouts{vertexDescriptorSetLayouts.size() + fragmentDescriptorSetLayouts.size()};
|
||||||
|
int i = 0;
|
||||||
|
for (auto&& descriptorSetLayout : vertexDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
layouts[i++] = descriptorSetLayout.second;
|
||||||
|
}
|
||||||
|
for (auto&& descriptorSetLayout : fragmentDescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
layouts[i++] = descriptorSetLayout.second;
|
||||||
|
}
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
|
||||||
|
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutCreateInfo.setLayoutCount = layouts.size();
|
||||||
|
pipelineLayoutCreateInfo.pSetLayouts = layouts.data();
|
||||||
|
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
|
||||||
|
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
|
||||||
|
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
graphicsPipelineCreateInfo.stageCount = 2;
|
||||||
|
graphicsPipelineCreateInfo.pStages = shaderStages;
|
||||||
|
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pDepthStencilState = nullptr;
|
||||||
|
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
||||||
|
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
||||||
|
graphicsPipelineCreateInfo.renderPass = instance.GetSwapChain().GetRenderPass();
|
||||||
|
graphicsPipelineCreateInfo.subpass = 0;
|
||||||
|
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
|
||||||
|
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), vertShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), fragShaderModule, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModule(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;
|
||||||
|
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayout InitializeDescriptorSetLayout(uint32_t binding, VkShaderStageFlags flags)
|
||||||
|
{
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
|
VkDescriptorSetLayoutBinding layoutBinding{};
|
||||||
|
layoutBinding.binding = binding;
|
||||||
|
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
layoutBinding.descriptorCount = 1;
|
||||||
|
layoutBinding.stageFlags = flags;
|
||||||
|
layoutBinding.pImmutableSamplers = nullptr;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
createInfo.bindingCount = 1;
|
||||||
|
createInfo.pBindings = &layoutBinding;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayout), "Failed to initialize descriptor set layout");
|
||||||
|
|
||||||
|
return descriptorSetLayout;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
class PipelineCreator
|
||||||
|
{
|
||||||
|
friend class Pipeline;
|
||||||
|
private:
|
||||||
|
std::set<uint32_t> vertexDescriptorSetLayouts{};
|
||||||
|
std::set<uint32_t> fragmentDescriptorSetLayouts{};
|
||||||
|
|
||||||
|
std::string vertexShader;
|
||||||
|
std::string fragmentShader;
|
||||||
|
VkVertexInputBindingDescription vertexInputBindingDescription;
|
||||||
|
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions{};
|
||||||
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader)
|
||||||
|
: vertexShader{vertexShader}, fragmentShader{fragmentShader}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetVertexInputBindingDescription(VkVertexInputBindingDescription description)
|
||||||
|
{
|
||||||
|
vertexInputBindingDescription = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetVertexInputAttributeDescription(const std::vector<VkVertexInputAttributeDescription>& descriptions)
|
||||||
|
{
|
||||||
|
vertexInputAttributeDescriptions = descriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddVertexDescriptorSetLayoutBinding(uint32_t binding)
|
||||||
|
{
|
||||||
|
vertexDescriptorSetLayouts.emplace(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddFragmentDescriptorSetLayoutBinding(uint32_t binding)
|
||||||
|
{
|
||||||
|
fragmentDescriptorSetLayouts.emplace(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
||||||
|
{
|
||||||
|
topology = primitiveTopology;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCullMode(VkCullModeFlags flags)
|
||||||
|
{
|
||||||
|
cullMode = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCullFrontFace(VkFrontFace cullFrontFace)
|
||||||
|
{
|
||||||
|
frontFace = cullFrontFace;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct QueueFamilies
|
struct QueueFamiliesQuery
|
||||||
{
|
{
|
||||||
std::optional<uint32_t> graphicsFamily;
|
std::optional<uint32_t> graphicsFamily;
|
||||||
std::optional<uint32_t> presentFamily;
|
std::optional<uint32_t> presentFamily;
|
||||||
|
|
||||||
QueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device)
|
QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device)
|
||||||
{
|
{
|
||||||
uint32_t queueFamilyCount = 0;
|
uint32_t queueFamilyCount = 0;
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
#include "QueueFamilies.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
#include <glfw/glfw3.h>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice)
|
||||||
|
{
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);
|
||||||
|
|
||||||
|
uint32_t formatCount;
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
|
||||||
|
if (formatCount != 0)
|
||||||
|
{
|
||||||
|
formats.resize(formatCount);
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t presentModeCount;
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
|
||||||
|
if (presentModeCount != 0)
|
||||||
|
{
|
||||||
|
presentModes.resize(presentModeCount);
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwapChainSupportDetails::Valid()
|
||||||
|
{
|
||||||
|
return !formats.empty() && !presentModes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapChain::SwapChain(Instance& instance)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
InitializeImageViews();
|
||||||
|
InitializeRenderPass();
|
||||||
|
InitializeFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapChain::~SwapChain()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainKHR SwapChain::GetHandle() const
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPass SwapChain::GetRenderPass() const
|
||||||
|
{
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D SwapChain::GetExtent() const
|
||||||
|
{
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFramebuffer SwapChain::GetFramebuffer() const
|
||||||
|
{
|
||||||
|
return framebuffers[imageIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwapChain::BeginPresent(VkSemaphore signalSemaphore)
|
||||||
|
{
|
||||||
|
VkResult result = vkAcquireNextImageKHR(instance.GetDevice(), handle, UINT64_MAX, signalSemaphore, VK_NULL_HANDLE, &imageIndex);
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||||
|
{
|
||||||
|
Recreate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized)
|
||||||
|
{
|
||||||
|
VkPresentInfoKHR presentInfo{};
|
||||||
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
|
presentInfo.pWaitSemaphores = waitSemaphore;
|
||||||
|
presentInfo.swapchainCount = 1;
|
||||||
|
presentInfo.pSwapchains = &handle;
|
||||||
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
presentInfo.pResults = nullptr;
|
||||||
|
|
||||||
|
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
|
||||||
|
{
|
||||||
|
Recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::Recreate()
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
|
||||||
|
while (width == 0 || height == 0)
|
||||||
|
{
|
||||||
|
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
|
||||||
|
glfwWaitEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDeviceWaitIdle(instance.GetDevice());
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
InitializeImageViews();
|
||||||
|
InitializeFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::Initialize()
|
||||||
|
{
|
||||||
|
SwapChainSupportDetails swapChainSupport{instance.GetSurface(), instance.GetPhysicalDevice()};
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
|
||||||
|
VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
|
||||||
|
extent = SelectSwapExtent(instance.GetWindow(), swapChainSupport.capabilities);
|
||||||
|
imageFormat = format.format;
|
||||||
|
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
|
||||||
|
if (swapChainSupport.capabilities.maxImageCount != 0)
|
||||||
|
{
|
||||||
|
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueFamiliesQuery queueFamilies{instance.GetSurface(), instance.GetPhysicalDevice()};
|
||||||
|
std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
createInfo.surface = instance.GetSurface();
|
||||||
|
createInfo.minImageCount = imageCount;
|
||||||
|
createInfo.imageFormat = format.format;
|
||||||
|
createInfo.imageColorSpace = format.colorSpace;
|
||||||
|
createInfo.imageExtent = extent;
|
||||||
|
createInfo.imageArrayLayers = 1;
|
||||||
|
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
|
||||||
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
createInfo.presentMode = presentMode;
|
||||||
|
createInfo.clipped = VK_TRUE;
|
||||||
|
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
|
||||||
|
{
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
|
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.queueFamilyIndexCount = 0;
|
||||||
|
createInfo.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateSwapchainKHR(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize the swapchain");
|
||||||
|
|
||||||
|
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, nullptr);
|
||||||
|
images.resize(imageCount);
|
||||||
|
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, images.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::InitializeImageViews()
|
||||||
|
{
|
||||||
|
imageViews.resize(images.size());
|
||||||
|
for (size_t i = 0; i < images.size(); i++)
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = images[i];
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = imageFormat;
|
||||||
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageViews[i]), "Failed to initialize swapchain image view");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::InitializeRenderPass()
|
||||||
|
{
|
||||||
|
VkAttachmentDescription colorAttachment{};
|
||||||
|
colorAttachment.format = imageFormat;
|
||||||
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
VkAttachmentReference colorAttachmentRef{};
|
||||||
|
colorAttachmentRef.attachment = 0;
|
||||||
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass{};
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &colorAttachmentRef;
|
||||||
|
|
||||||
|
VkSubpassDependency dependency{};
|
||||||
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
dependency.dstSubpass = 0;
|
||||||
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependency.dstStageMask = 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;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo renderPassCreateInfo{};
|
||||||
|
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassCreateInfo.attachmentCount = 1;
|
||||||
|
renderPassCreateInfo.pAttachments = &colorAttachment;
|
||||||
|
renderPassCreateInfo.subpassCount = 1;
|
||||||
|
renderPassCreateInfo.pSubpasses = &subpass;
|
||||||
|
renderPassCreateInfo.dependencyCount = 1;
|
||||||
|
renderPassCreateInfo.pDependencies = &dependency;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::InitializeFramebuffers()
|
||||||
|
{
|
||||||
|
framebuffers.resize(images.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < imageViews.size(); ++i)
|
||||||
|
{
|
||||||
|
VkImageView attachments[] = {imageViews[i]};
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
createInfo.renderPass = renderPass;
|
||||||
|
createInfo.attachmentCount = 1;
|
||||||
|
createInfo.pAttachments = attachments;
|
||||||
|
createInfo.width = extent.width;
|
||||||
|
createInfo.height = extent.height;
|
||||||
|
createInfo.layers = 1;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::Destroy()
|
||||||
|
{
|
||||||
|
for (auto&& framebuffer : framebuffers)
|
||||||
|
{
|
||||||
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
for (auto&& swapChainImageView : imageViews)
|
||||||
|
{
|
||||||
|
vkDestroyImageView(instance.GetDevice(), swapChainImageView, nullptr);
|
||||||
|
}
|
||||||
|
vkDestroySwapchainKHR(instance.GetDevice(), handle, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
||||||
|
{
|
||||||
|
for (auto&& availableFormat : availableFormats)
|
||||||
|
{
|
||||||
|
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
{
|
||||||
|
return availableFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return availableFormats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
||||||
|
{
|
||||||
|
for (auto&& availablePresentMode : availablePresentModes)
|
||||||
|
{
|
||||||
|
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||||
|
{
|
||||||
|
return availablePresentMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D SwapChain::SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
|
||||||
|
{
|
||||||
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
|
||||||
|
VkExtent2D extent{width, height};
|
||||||
|
extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
|
||||||
|
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
+25
-373
@@ -1,53 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "QueueFamilies.h"
|
|
||||||
#include <glfw/glfw3.h>
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class Instance;
|
||||||
|
|
||||||
struct SwapChainSupportDetails
|
struct SwapChainSupportDetails
|
||||||
{
|
{
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
std::vector<VkPresentModeKHR> presentModes;
|
std::vector<VkPresentModeKHR> presentModes;
|
||||||
|
|
||||||
SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice device)
|
SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice);
|
||||||
{
|
bool Valid();
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities);
|
|
||||||
|
|
||||||
uint32_t formatCount;
|
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
|
||||||
if (formatCount != 0)
|
|
||||||
{
|
|
||||||
formats.resize(formatCount);
|
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, formats.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t presentModeCount;
|
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
|
|
||||||
if (presentModeCount != 0)
|
|
||||||
{
|
|
||||||
presentModes.resize(presentModeCount);
|
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Valid()
|
|
||||||
{
|
|
||||||
return !formats.empty() && !presentModes.empty();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SwapChain
|
class SwapChain final
|
||||||
{
|
{
|
||||||
// TODO: Remove, replaced by Instance::MAX_FRAMES_IN_FLIGHT
|
CP_DELETE_COPY_AND_MOVE_CTOR(SwapChain);
|
||||||
static const int MAX_FRAMES_IN_FLIGHT = 2;
|
private:
|
||||||
|
Instance& instance;
|
||||||
// Needed for recreation and destruction
|
|
||||||
GLFWwindow* window;
|
|
||||||
VkSurfaceKHR surface;
|
|
||||||
VkPhysicalDevice physicalDevice;
|
|
||||||
VkDevice device;
|
|
||||||
|
|
||||||
// Created by the class
|
// Created by the class
|
||||||
VkSwapchainKHR handle;
|
VkSwapchainKHR handle;
|
||||||
@@ -58,349 +30,29 @@ class SwapChain
|
|||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
std::vector<VkFramebuffer> framebuffers;
|
std::vector<VkFramebuffer> framebuffers;
|
||||||
|
|
||||||
int flightIndex;
|
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
|
||||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
|
||||||
std::vector<VkFence> inFlightFences;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SwapChain(GLFWwindow* window, VkSurfaceKHR surface, VkDevice device, VkPhysicalDevice physicalDevice)
|
SwapChain(Instance& instance);
|
||||||
: window{window}, surface{surface}, physicalDevice{physicalDevice}, device{device}
|
~SwapChain();
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
InitializeImageViews();
|
|
||||||
InitializeRenderPass();
|
|
||||||
InitializeFramebuffers();
|
|
||||||
InitializeSyncObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
~SwapChain()
|
VkSwapchainKHR GetHandle() const;
|
||||||
{
|
VkRenderPass GetRenderPass() const;
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
VkExtent2D GetExtent() const;
|
||||||
{
|
VkFramebuffer GetFramebuffer() const;
|
||||||
vkDestroyFence(device, inFlightFences[i], nullptr);
|
bool BeginPresent(VkSemaphore signalSemaphore);
|
||||||
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
|
void EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized);
|
||||||
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
|
void Recreate();
|
||||||
}
|
|
||||||
Destroy();
|
|
||||||
vkDestroyRenderPass(device, renderPass, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSwapchainKHR GetHandle() const
|
|
||||||
{
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkRenderPass GetRenderPass() const
|
|
||||||
{
|
|
||||||
return renderPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D GetExtent() const
|
|
||||||
{
|
|
||||||
return extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFramebuffer GetFramebuffer() const
|
|
||||||
{
|
|
||||||
return framebuffers[imageIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BeginPresent()
|
|
||||||
{
|
|
||||||
vkWaitForFences(device, 1, &inFlightFences[flightIndex], VK_TRUE, UINT64_MAX);
|
|
||||||
|
|
||||||
VkResult result = vkAcquireNextImageKHR(device, handle, UINT64_MAX, imageAvailableSemaphores[flightIndex], VK_NULL_HANDLE, &imageIndex);
|
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
|
||||||
{
|
|
||||||
Recreate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkResetFences(device, 1, &inFlightFences[flightIndex]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndPresent(VkQueue presentQueue, bool framebufferResized)
|
|
||||||
{
|
|
||||||
VkSwapchainKHR swapChains[] = {handle};
|
|
||||||
VkPresentInfoKHR presentInfo{};
|
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
|
||||||
presentInfo.pWaitSemaphores = &renderFinishedSemaphores[flightIndex];
|
|
||||||
presentInfo.swapchainCount = 1;
|
|
||||||
presentInfo.pSwapchains = &handle;
|
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
|
||||||
presentInfo.pResults = nullptr;
|
|
||||||
|
|
||||||
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
|
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
|
|
||||||
{
|
|
||||||
framebufferResized = false;
|
|
||||||
Recreate();
|
|
||||||
}
|
|
||||||
|
|
||||||
flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetFlightIndex() const
|
|
||||||
{
|
|
||||||
return flightIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetMaxFramesInFlight() const
|
|
||||||
{
|
|
||||||
return MAX_FRAMES_IN_FLIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFence GetInFlightFence() const
|
|
||||||
{
|
|
||||||
return inFlightFences[flightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSemaphore GetAvailableImageSemaphore() const
|
|
||||||
{
|
|
||||||
return imageAvailableSemaphores[flightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSemaphore GetRenderFinishedSemaphore() const
|
|
||||||
{
|
|
||||||
return renderFinishedSemaphores[flightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Recreate()
|
|
||||||
{
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
|
||||||
while (width == 0 || height == 0)
|
|
||||||
{
|
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
|
||||||
glfwWaitEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
|
|
||||||
Initialize();
|
|
||||||
InitializeImageViews();
|
|
||||||
InitializeFramebuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void Initialize();
|
||||||
|
void InitializeImageViews();
|
||||||
|
void InitializeRenderPass();
|
||||||
|
void InitializeFramebuffers();
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
void Initialize()
|
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||||
{
|
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
||||||
SwapChainSupportDetails swapChainSupport{surface, physicalDevice};
|
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
|
|
||||||
VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
|
|
||||||
VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
|
|
||||||
extent = SelectSwapExtent(window, swapChainSupport.capabilities);
|
|
||||||
imageFormat = format.format;
|
|
||||||
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
|
|
||||||
if (swapChainSupport.capabilities.maxImageCount != 0)
|
|
||||||
{
|
|
||||||
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
QueueFamilies queueFamilies{surface, physicalDevice};
|
|
||||||
std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
||||||
createInfo.surface = surface;
|
|
||||||
createInfo.minImageCount = imageCount;
|
|
||||||
createInfo.imageFormat = format.format;
|
|
||||||
createInfo.imageColorSpace = format.colorSpace;
|
|
||||||
createInfo.imageExtent = extent;
|
|
||||||
createInfo.imageArrayLayers = 1;
|
|
||||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
||||||
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
|
|
||||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
||||||
createInfo.presentMode = presentMode;
|
|
||||||
createInfo.clipped = VK_TRUE;
|
|
||||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
|
||||||
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
|
|
||||||
{
|
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
||||||
createInfo.queueFamilyIndexCount = 2;
|
|
||||||
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
createInfo.queueFamilyIndexCount = 0;
|
|
||||||
createInfo.pQueueFamilyIndices = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateSwapchainKHR(device, &createInfo, nullptr, &handle), "Failed to initialize the swapchain");
|
|
||||||
|
|
||||||
vkGetSwapchainImagesKHR(device, handle, &imageCount, nullptr);
|
|
||||||
images.resize(imageCount);
|
|
||||||
vkGetSwapchainImagesKHR(device, handle, &imageCount, images.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeImageViews()
|
|
||||||
{
|
|
||||||
imageViews.resize(images.size());
|
|
||||||
for (size_t i = 0; i < images.size(); i++)
|
|
||||||
{
|
|
||||||
VkImageViewCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
createInfo.image = images[i];
|
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
createInfo.format = imageFormat;
|
|
||||||
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
createInfo.subresourceRange.baseMipLevel = 0;
|
|
||||||
createInfo.subresourceRange.levelCount = 1;
|
|
||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
|
||||||
VK_ASSERT(vkCreateImageView(device, &createInfo, nullptr, &imageViews[i]), "Failed to initialize swapchain image view");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeRenderPass()
|
|
||||||
{
|
|
||||||
VkAttachmentDescription colorAttachment{};
|
|
||||||
colorAttachment.format = imageFormat;
|
|
||||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
||||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
||||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
||||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
||||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
||||||
|
|
||||||
VkAttachmentReference colorAttachmentRef{};
|
|
||||||
colorAttachmentRef.attachment = 0;
|
|
||||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
||||||
|
|
||||||
VkSubpassDescription subpass{};
|
|
||||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
||||||
subpass.colorAttachmentCount = 1;
|
|
||||||
subpass.pColorAttachments = &colorAttachmentRef;
|
|
||||||
|
|
||||||
VkSubpassDependency dependency{};
|
|
||||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
||||||
dependency.dstSubpass = 0;
|
|
||||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
dependency.srcAccessMask = 0;
|
|
||||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
||||||
|
|
||||||
VkRenderPassCreateInfo renderPassCreateInfo{};
|
|
||||||
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
||||||
renderPassCreateInfo.attachmentCount = 1;
|
|
||||||
renderPassCreateInfo.pAttachments = &colorAttachment;
|
|
||||||
renderPassCreateInfo.subpassCount = 1;
|
|
||||||
renderPassCreateInfo.pSubpasses = &subpass;
|
|
||||||
renderPassCreateInfo.dependencyCount = 1;
|
|
||||||
renderPassCreateInfo.pDependencies = &dependency;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeFramebuffers()
|
|
||||||
{
|
|
||||||
framebuffers.resize(images.size());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < imageViews.size(); ++i)
|
|
||||||
{
|
|
||||||
VkImageView attachments[] = {imageViews[i]};
|
|
||||||
|
|
||||||
VkFramebufferCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
||||||
createInfo.renderPass = renderPass;
|
|
||||||
createInfo.attachmentCount = 1;
|
|
||||||
createInfo.pAttachments = attachments;
|
|
||||||
createInfo.width = extent.width;
|
|
||||||
createInfo.height = extent.height;
|
|
||||||
createInfo.layers = 1;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateFramebuffer(device, &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeSyncObjects()
|
|
||||||
{
|
|
||||||
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
|
||||||
VkSemaphoreCreateInfo semaphoreCreateInfo{};
|
|
||||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
|
||||||
{
|
|
||||||
VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
|
|
||||||
VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
|
|
||||||
|
|
||||||
VkFenceCreateInfo fenceCreateInfo{};
|
|
||||||
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
for (auto&& framebuffer : framebuffers)
|
|
||||||
{
|
|
||||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
|
||||||
}
|
|
||||||
for (auto&& swapChainImageView : imageViews)
|
|
||||||
{
|
|
||||||
vkDestroyImageView(device, swapChainImageView, nullptr);
|
|
||||||
}
|
|
||||||
vkDestroySwapchainKHR(device, handle, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
|
||||||
{
|
|
||||||
for (auto&& availableFormat : availableFormats)
|
|
||||||
{
|
|
||||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
|
||||||
{
|
|
||||||
return availableFormat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return availableFormats[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
|
||||||
{
|
|
||||||
for (auto&& availablePresentMode : availablePresentModes)
|
|
||||||
{
|
|
||||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
|
||||||
{
|
|
||||||
return availablePresentMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
|
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
|
|
||||||
{
|
|
||||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
|
||||||
return capabilities.currentExtent;
|
|
||||||
|
|
||||||
int width, height;
|
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
|
||||||
|
|
||||||
VkExtent2D extent{width, height};
|
|
||||||
extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
|
|
||||||
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
|
|
||||||
return extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> startTime;
|
||||||
|
public:
|
||||||
|
Timer()
|
||||||
|
: startTime{std::chrono::steady_clock::now()}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
startTime = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Elapsed()
|
||||||
|
{
|
||||||
|
return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Pipeline.h"
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class UniformBuffer : public Buffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
|
||||||
|
private:
|
||||||
|
Pipeline& pipeline;
|
||||||
|
|
||||||
|
VkDescriptorPool descriptorPool;
|
||||||
|
std::vector<VkDescriptorSet> descriptorSets;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniformBuffer(Instance& instance, Pipeline& pipeline, uint32_t binding, VkDescriptorSetLayout layout)
|
||||||
|
: Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(T), instance.GetMaxFramesInFlight()}, pipeline{pipeline}
|
||||||
|
{
|
||||||
|
InitializeDescriptorPool();
|
||||||
|
InitializeDescriptorSet(binding, layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
~UniformBuffer() override
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(const T& t)
|
||||||
|
{
|
||||||
|
Buffer::Update((void*)&t, instance.GetFlightIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bind(VkCommandBuffer commandBuffer) const
|
||||||
|
{
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetPipelineLayout(), 0, 1, &descriptorSets[instance.GetFlightIndex()], 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeDescriptorPool()
|
||||||
|
{
|
||||||
|
VkDescriptorPoolSize poolSize{};
|
||||||
|
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
poolSize.descriptorCount = instance.GetMaxFramesInFlight();
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
createInfo.poolSizeCount = 1;
|
||||||
|
createInfo.pPoolSizes = &poolSize;
|
||||||
|
createInfo.maxSets = instance.GetMaxFramesInFlight();
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeDescriptorSet(uint32_t binding, VkDescriptorSetLayout layout)
|
||||||
|
{
|
||||||
|
std::vector<VkDescriptorSetLayout> layouts{static_cast<size_t>(instance.GetMaxFramesInFlight()), layout};
|
||||||
|
VkDescriptorSetAllocateInfo allocateInfo{};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocateInfo.descriptorPool = descriptorPool;
|
||||||
|
allocateInfo.descriptorSetCount = instance.GetMaxFramesInFlight();
|
||||||
|
allocateInfo.pSetLayouts = layouts.data();
|
||||||
|
|
||||||
|
descriptorSets.resize(instance.GetMaxFramesInFlight());
|
||||||
|
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
|
||||||
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
||||||
|
VkDescriptorBufferInfo bufferInfo = GetDescriptorBufferInfo(i);
|
||||||
|
|
||||||
|
VkWriteDescriptorSet descriptorWrite{};
|
||||||
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptorWrite.dstSet = descriptorSets[i];
|
||||||
|
descriptorWrite.dstBinding = binding;
|
||||||
|
descriptorWrite.dstArrayElement = 0;
|
||||||
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
descriptorWrite.descriptorCount = 1;
|
||||||
|
descriptorWrite.pBufferInfo = &bufferInfo;
|
||||||
|
descriptorWrite.pImageInfo = nullptr;
|
||||||
|
descriptorWrite.pTexelBufferView = nullptr;
|
||||||
|
vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index)
|
||||||
|
{
|
||||||
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
bufferInfo.buffer = handle;
|
||||||
|
bufferInfo.offset = (VkDeviceSize)index * size;
|
||||||
|
bufferInfo.range = size;
|
||||||
|
return bufferInfo;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
glm::vec2 pos;
|
||||||
|
glm::vec3 color;
|
||||||
|
|
||||||
|
static VertexDescriptor GetDescriptor()
|
||||||
|
{
|
||||||
|
VertexDescriptor descriptor{};
|
||||||
|
descriptor.AddAttribute<Vertex>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, pos));
|
||||||
|
descriptor.AddAttribute<Vertex>(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VkVertexInputBindingDescription GetBindingDescription()
|
||||||
|
{
|
||||||
|
VkVertexInputBindingDescription description{};
|
||||||
|
|
||||||
|
description.binding = 0;
|
||||||
|
description.stride = sizeof(Vertex);
|
||||||
|
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<VkVertexInputAttributeDescription> GetAttributeDescriptions()
|
||||||
|
{
|
||||||
|
std::vector<VkVertexInputAttributeDescription> descriptions{2};
|
||||||
|
|
||||||
|
descriptions[0].binding = 0;
|
||||||
|
descriptions[0].location = 0;
|
||||||
|
descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
descriptions[0].offset = offsetof(Vertex, pos);
|
||||||
|
|
||||||
|
descriptions[1].binding = 0;
|
||||||
|
descriptions[1].location = 1;
|
||||||
|
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
descriptions[1].offset = offsetof(Vertex, color);
|
||||||
|
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
|
class VertexBuffer : public Buffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(VertexBuffer);
|
||||||
|
std::map<uint32_t, VkDeviceSize> bindingOffsets;
|
||||||
|
std::map<uint32_t, VkDeviceSize> bindingSizes;
|
||||||
|
public:
|
||||||
|
VertexBuffer(Instance& instance, VkDeviceSize size)
|
||||||
|
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, size, 1}
|
||||||
|
{}
|
||||||
|
|
||||||
|
VertexBuffer(Instance& instance, const VertexDescriptor& descriptor, int vertexCount)
|
||||||
|
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, descriptor.GetVertexSize() * vertexCount, 1}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Bind(VkCommandBuffer commandBuffer) override
|
||||||
|
{
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &handle, &offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(uint32_t binding, void* data)
|
||||||
|
{
|
||||||
|
UpdateStaging(data, bindingOffsets[binding], bindingSizes[binding]);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
class VertexDescriptor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint32_t bindingIndex = 0;
|
||||||
|
std::vector<VkVertexInputBindingDescription> bindings;
|
||||||
|
std::vector<VkVertexInputAttributeDescription> attributes;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(bindings.begin(), bindings.end(), [&binding](const VkVertexInputBindingDescription& description) { return description.binding == binding; });
|
||||||
|
if (it == bindings.end())
|
||||||
|
AddLayout(binding, sizeof(T));
|
||||||
|
|
||||||
|
VkVertexInputAttributeDescription description{};
|
||||||
|
description.binding = binding;
|
||||||
|
description.location = location;
|
||||||
|
description.format = format;
|
||||||
|
description.offset = offset;
|
||||||
|
attributes.emplace_back(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize GetVertexSize() const
|
||||||
|
{
|
||||||
|
VkDeviceSize bufferSize = 0;
|
||||||
|
for (auto&& binding : bindings)
|
||||||
|
{
|
||||||
|
bufferSize += binding.stride;
|
||||||
|
}
|
||||||
|
return bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t AddLayout(uint32_t binding, uint32_t size)
|
||||||
|
{
|
||||||
|
VkVertexInputBindingDescription description{};
|
||||||
|
description.binding = binding;
|
||||||
|
description.stride = size;
|
||||||
|
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
bindings.emplace_back(description);
|
||||||
|
return description.binding;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
class VulkanException : public std::runtime_error
|
class VulkanException : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanException(const char* str)
|
VulkanException(const std::string& str)
|
||||||
: runtime_error{str}
|
: runtime_error{str.c_str()}
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
+59
-315
@@ -1,13 +1,14 @@
|
|||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "IndexBuffer.h"
|
||||||
|
#include "VertexBuffer.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#define GLM_FORCE_LEFT_HANDED
|
#include "Timer.h"
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#include "UniformBuffer.h"
|
||||||
|
#include "Vertex.h"
|
||||||
|
#include "Pipeline.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -16,39 +17,6 @@
|
|||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
struct Vertex {
|
|
||||||
glm::vec2 pos;
|
|
||||||
glm::vec3 color;
|
|
||||||
|
|
||||||
static VkVertexInputBindingDescription getBindingDescription()
|
|
||||||
{
|
|
||||||
VkVertexInputBindingDescription description{};
|
|
||||||
|
|
||||||
description.binding = 0;
|
|
||||||
description.stride = sizeof(Vertex);
|
|
||||||
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
||||||
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<VkVertexInputAttributeDescription> getAttributeDescriptions()
|
|
||||||
{
|
|
||||||
std::vector<VkVertexInputAttributeDescription> descriptions{2};
|
|
||||||
|
|
||||||
descriptions[0].binding = 0;
|
|
||||||
descriptions[0].location = 0;
|
|
||||||
descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
|
||||||
descriptions[0].offset = offsetof(Vertex, pos);
|
|
||||||
|
|
||||||
descriptions[1].binding = 0;
|
|
||||||
descriptions[1].location = 1;
|
|
||||||
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
descriptions[1].offset = offsetof(Vertex, color);
|
|
||||||
|
|
||||||
return descriptions;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Vertex> vertices = {
|
const std::vector<Vertex> vertices = {
|
||||||
Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||||
Vertex{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
Vertex{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||||
@@ -60,7 +28,7 @@ const std::vector<uint16_t> indices = {
|
|||||||
0, 1, 2, 2, 3, 0
|
0, 1, 2, 2, 3, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UniformBufferObject
|
struct ShaderUniform
|
||||||
{
|
{
|
||||||
glm::mat4 model;
|
glm::mat4 model;
|
||||||
glm::mat4 view;
|
glm::mat4 view;
|
||||||
@@ -71,42 +39,26 @@ class Application final
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Instance> instance;
|
std::unique_ptr<Instance> instance;
|
||||||
VkDescriptorSetLayout uniformBufferLayout;
|
std::unique_ptr<Pipeline> graphicsPipeline;
|
||||||
VkDescriptorPool descriptorPool;
|
std::unique_ptr<VertexBuffer> vertexBuffer;
|
||||||
std::vector<VkDescriptorSet> descriptorSets;
|
std::unique_ptr<IndexBuffer> indexBuffer;
|
||||||
VkPipelineLayout pipelineLayout;
|
std::unique_ptr<UniformBuffer<ShaderUniform>> uniformBuffer;
|
||||||
VkPipeline graphicsPipeline;
|
|
||||||
std::unique_ptr<Buffer> vertexBuffer;
|
|
||||||
std::unique_ptr<Buffer> indexBuffer;
|
|
||||||
std::unique_ptr<Buffer> uniformBuffer;
|
|
||||||
std::vector<VkCommandBuffer> commandBuffers;
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
UniformBufferObject uniformBufferObject;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application()
|
Application()
|
||||||
{
|
{
|
||||||
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
InitializeInstance();
|
||||||
InitializeUniformBufferLayout();
|
|
||||||
InitializeGraphicsPipeline();
|
InitializeGraphicsPipeline();
|
||||||
|
InitializeUniformBuffer();
|
||||||
InitializeVertexBuffer();
|
InitializeVertexBuffer();
|
||||||
InitializeIndexBuffer();
|
InitializeIndexBuffer();
|
||||||
InitializeUniformBuffer();
|
InitializeCommandBuffers();
|
||||||
InitializeDescriptorPool();
|
|
||||||
InitializeDescriptorSet();
|
|
||||||
InitializeCommandBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Application()
|
~Application()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(instance->GetDevice());
|
vkDeviceWaitIdle(instance->GetDevice());
|
||||||
uniformBuffer.reset();
|
|
||||||
vertexBuffer.reset();
|
|
||||||
indexBuffer.reset();
|
|
||||||
vkDestroyPipeline(instance->GetDevice(), graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(instance->GetDevice(), pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(instance->GetDevice(), descriptorPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(instance->GetDevice(), uniformBufferLayout, nullptr);
|
|
||||||
instance.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application(Application&&) = delete;
|
Application(Application&&) = delete;
|
||||||
@@ -119,250 +71,48 @@ public:
|
|||||||
if (!instance->BeginPresent())
|
if (!instance->BeginPresent())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RecordCommandBuffer(commandBuffers[instance->GetSwapChain().GetFlightIndex()]);
|
RecordCommandBuffer(commandBuffers[instance->GetFlightIndex()]);
|
||||||
|
|
||||||
instance->SubmitGraphicsQueue(std::vector<VkCommandBuffer>{commandBuffers[instance->GetSwapChain().GetFlightIndex()]});
|
instance->SubmitGraphicsQueue(std::vector<VkCommandBuffer>{commandBuffers[instance->GetFlightIndex()]});
|
||||||
return instance->EndPresent();
|
return instance->EndPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void InitializeUniformBufferLayout()
|
void InitializeInstance()
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
||||||
layoutBinding.binding = 0;
|
|
||||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
layoutBinding.descriptorCount = 1;
|
|
||||||
layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
layoutBinding.pImmutableSamplers = nullptr;
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
createInfo.bindingCount = 1;
|
|
||||||
createInfo.pBindings = &layoutBinding;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateDescriptorSetLayout(instance->GetDevice(), &createInfo, nullptr, &uniformBufferLayout), "Failed to initialize uniform buffer layout");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeDescriptorPool()
|
void InitializeUniformBuffer()
|
||||||
{
|
{
|
||||||
VkDescriptorPoolSize poolSize{};
|
uniformBuffer = std::make_unique<UniformBuffer<ShaderUniform>>(*instance, *graphicsPipeline, 0, graphicsPipeline->GetVertexDescriptorSetLayout(0));
|
||||||
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
poolSize.descriptorCount = instance->GetMaxFramesInFlight();
|
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
||||||
createInfo.poolSizeCount = 1;
|
|
||||||
createInfo.pPoolSizes = &poolSize;
|
|
||||||
createInfo.maxSets = instance->GetMaxFramesInFlight();
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateDescriptorPool(instance->GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeDescriptorSet()
|
|
||||||
{
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts{static_cast<size_t>(instance->GetMaxFramesInFlight()), uniformBufferLayout};
|
|
||||||
VkDescriptorSetAllocateInfo allocateInfo{};
|
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
allocateInfo.descriptorPool = descriptorPool;
|
|
||||||
allocateInfo.descriptorSetCount = instance->GetMaxFramesInFlight();
|
|
||||||
allocateInfo.pSetLayouts = layouts.data();
|
|
||||||
|
|
||||||
descriptorSets.resize(instance->GetMaxFramesInFlight());
|
|
||||||
VK_ASSERT(vkAllocateDescriptorSets(instance->GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
|
|
||||||
for (size_t i = 0; i < instance->GetMaxFramesInFlight(); ++i) {
|
|
||||||
VkDescriptorBufferInfo bufferInfo = uniformBuffer->GetDescriptorBufferInfo(i);
|
|
||||||
|
|
||||||
VkWriteDescriptorSet descriptorWrite{};
|
|
||||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
||||||
descriptorWrite.dstSet = descriptorSets[i];
|
|
||||||
descriptorWrite.dstBinding = 0;
|
|
||||||
descriptorWrite.dstArrayElement = 0;
|
|
||||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
descriptorWrite.descriptorCount = 1;
|
|
||||||
descriptorWrite.pBufferInfo = &bufferInfo;
|
|
||||||
descriptorWrite.pImageInfo = nullptr;
|
|
||||||
descriptorWrite.pTexelBufferView = nullptr;
|
|
||||||
vkUpdateDescriptorSets(instance->GetDevice(), 1, &descriptorWrite, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeGraphicsPipeline()
|
void InitializeGraphicsPipeline()
|
||||||
{
|
{
|
||||||
std::vector<char> vertShaderCode = FileSystem::ReadFile("res/shaders/vert.spv");
|
PipelineCreator creator{"res/shaders/vert.spv", "res/shaders/frag.spv"};
|
||||||
std::vector<char> fragShaderCode = FileSystem::ReadFile("res/shaders/frag.spv");
|
creator.AddVertexDescriptorSetLayoutBinding(0);
|
||||||
|
creator.SetVertexInputBindingDescription(Vertex::GetBindingDescription());
|
||||||
VkShaderModule vertShaderModule = InitializeShaderModule(vertShaderCode);
|
creator.SetVertexInputAttributeDescription(Vertex::GetAttributeDescriptions());
|
||||||
VkShaderModule fragShaderModule = InitializeShaderModule(fragShaderCode);
|
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo shaderStages[2];
|
|
||||||
shaderStages[0] = {};
|
|
||||||
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
||||||
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
||||||
shaderStages[0].module = vertShaderModule;
|
|
||||||
shaderStages[0].pName = "main";
|
|
||||||
|
|
||||||
shaderStages[1] = {};
|
|
||||||
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
||||||
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
shaderStages[1].module = fragShaderModule;
|
|
||||||
shaderStages[1].pName = "main";
|
|
||||||
|
|
||||||
VkVertexInputBindingDescription bindingDescriptions{Vertex::getBindingDescription()};
|
|
||||||
std::vector<VkVertexInputAttributeDescription> attributeDescriptions{Vertex::getAttributeDescriptions()};
|
|
||||||
|
|
||||||
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
|
|
||||||
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
||||||
vertexInputCreateInfo.vertexBindingDescriptionCount = 1;
|
|
||||||
vertexInputCreateInfo.pVertexBindingDescriptions = &bindingDescriptions;
|
|
||||||
vertexInputCreateInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
|
|
||||||
vertexInputCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
|
|
||||||
|
|
||||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
|
|
||||||
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
||||||
inputAssemblyCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
||||||
inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
|
|
||||||
|
|
||||||
VkViewport viewport{};
|
|
||||||
viewport.x = 0;
|
|
||||||
viewport.y = 0;
|
|
||||||
viewport.width = instance->GetSwapChain().GetExtent().width;
|
|
||||||
viewport.height = instance->GetSwapChain().GetExtent().height;
|
|
||||||
viewport.minDepth = 0.0f;
|
|
||||||
viewport.maxDepth = 1.0f;
|
|
||||||
|
|
||||||
VkRect2D scissor{};
|
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = instance->GetSwapChain().GetExtent();
|
|
||||||
|
|
||||||
std::vector<VkDynamicState> dynamicStates = {
|
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
|
||||||
VK_DYNAMIC_STATE_SCISSOR
|
|
||||||
};
|
|
||||||
|
|
||||||
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{};
|
|
||||||
dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
||||||
dynamicStateCreateInfo.dynamicStateCount = dynamicStates.size();
|
|
||||||
dynamicStateCreateInfo.pDynamicStates = dynamicStates.data();
|
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo viewportStateCreateInfo{};
|
|
||||||
viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
||||||
viewportStateCreateInfo.viewportCount = 1;
|
|
||||||
viewportStateCreateInfo.pViewports = &viewport;
|
|
||||||
viewportStateCreateInfo.scissorCount = 1;
|
|
||||||
viewportStateCreateInfo.pScissors = &scissor;
|
|
||||||
|
|
||||||
VkPipelineRasterizationStateCreateInfo rasterizerCreateInfo{};
|
|
||||||
rasterizerCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
||||||
rasterizerCreateInfo.depthClampEnable = VK_FALSE;
|
|
||||||
rasterizerCreateInfo.rasterizerDiscardEnable = VK_FALSE;
|
|
||||||
rasterizerCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
|
|
||||||
rasterizerCreateInfo.lineWidth = 1.0f;
|
|
||||||
rasterizerCreateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
|
|
||||||
rasterizerCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
|
||||||
|
|
||||||
rasterizerCreateInfo.depthBiasEnable = VK_FALSE;
|
|
||||||
rasterizerCreateInfo.depthBiasConstantFactor = 0.0f;
|
|
||||||
rasterizerCreateInfo.depthBiasClamp = 0.0f;
|
|
||||||
rasterizerCreateInfo.depthBiasSlopeFactor = 0.0f;
|
|
||||||
|
|
||||||
VkPipelineMultisampleStateCreateInfo multisampleCreateInfo{};
|
|
||||||
multisampleCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
||||||
multisampleCreateInfo.sampleShadingEnable = VK_FALSE;
|
|
||||||
multisampleCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
multisampleCreateInfo.minSampleShading = 1.0f;
|
|
||||||
multisampleCreateInfo.pSampleMask = nullptr;
|
|
||||||
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
|
|
||||||
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
|
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
|
|
||||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
|
||||||
VK_COLOR_COMPONENT_G_BIT |
|
|
||||||
VK_COLOR_COMPONENT_B_BIT |
|
|
||||||
VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
colorBlendAttachment.blendEnable = VK_FALSE;
|
|
||||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
||||||
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
||||||
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
|
|
||||||
VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo{};
|
|
||||||
colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
||||||
colorBlendCreateInfo.logicOpEnable = VK_FALSE;
|
|
||||||
colorBlendCreateInfo.logicOp = VK_LOGIC_OP_COPY;
|
|
||||||
colorBlendCreateInfo.attachmentCount = 1;
|
|
||||||
colorBlendCreateInfo.pAttachments = &colorBlendAttachment;
|
|
||||||
colorBlendCreateInfo.blendConstants[0] = 0.0f;
|
|
||||||
colorBlendCreateInfo.blendConstants[1] = 0.0f;
|
|
||||||
colorBlendCreateInfo.blendConstants[2] = 0.0f;
|
|
||||||
colorBlendCreateInfo.blendConstants[3] = 0.0f;
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
|
|
||||||
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
||||||
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
|
||||||
pipelineLayoutCreateInfo.pSetLayouts = &uniformBufferLayout;
|
|
||||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
|
|
||||||
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreatePipelineLayout(instance->GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
|
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
|
|
||||||
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
||||||
graphicsPipelineCreateInfo.stageCount = 2;
|
|
||||||
graphicsPipelineCreateInfo.pStages = shaderStages;
|
|
||||||
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pDepthStencilState = nullptr;
|
|
||||||
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
|
||||||
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
|
||||||
graphicsPipelineCreateInfo.renderPass = instance->GetSwapChain().GetRenderPass();
|
|
||||||
graphicsPipelineCreateInfo.subpass = 0;
|
|
||||||
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
|
||||||
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
|
||||||
|
|
||||||
VK_ASSERT(vkCreateGraphicsPipelines(instance->GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
|
|
||||||
|
|
||||||
vkDestroyShaderModule(instance->GetDevice(), vertShaderModule, nullptr);
|
|
||||||
vkDestroyShaderModule(instance->GetDevice(), fragShaderModule, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeVertexBuffer()
|
void InitializeVertexBuffer()
|
||||||
{
|
{
|
||||||
VkDeviceSize bufferSize = sizeof(Vertex) * vertices.size();
|
VkDeviceSize bufferSize = sizeof(Vertex) * vertices.size();
|
||||||
Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
vertexBuffer = std::make_unique<VertexBuffer>(*instance, bufferSize);
|
||||||
|
vertexBuffer->UpdateStaging((void*)vertices.data());
|
||||||
stagingBuffer.Update((void*)vertices.data(), 0);
|
|
||||||
|
|
||||||
vertexBuffer = std::make_unique<Buffer>(*instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bufferSize, 1);
|
|
||||||
Buffer::CopyBuffer(*instance, stagingBuffer, *vertexBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeIndexBuffer()
|
void InitializeIndexBuffer()
|
||||||
{
|
{
|
||||||
VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size();
|
VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size();
|
||||||
Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
|
||||||
|
indexBuffer->UpdateStaging((void*)indices.data());
|
||||||
stagingBuffer.Update((void*)indices.data(), 0);
|
|
||||||
|
|
||||||
indexBuffer = std::make_unique<Buffer>(*instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bufferSize, 1);
|
|
||||||
Buffer::CopyBuffer(*instance, stagingBuffer, *indexBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeUniformBuffer()
|
void InitializeCommandBuffers()
|
||||||
{
|
|
||||||
VkDeviceSize bufferSize = sizeof(UniformBufferObject) * instance->GetMaxFramesInFlight();
|
|
||||||
uniformBuffer = std::make_unique<Buffer>(*instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, instance->GetMaxFramesInFlight());
|
|
||||||
uniformBuffer->Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeCommandBuffer()
|
|
||||||
{
|
{
|
||||||
commandBuffers.resize(instance->GetMaxFramesInFlight());
|
commandBuffers.resize(instance->GetMaxFramesInFlight());
|
||||||
VkCommandBufferAllocateInfo allocateInfo{};
|
VkCommandBufferAllocateInfo allocateInfo{};
|
||||||
@@ -371,7 +121,7 @@ private:
|
|||||||
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
allocateInfo.commandBufferCount = commandBuffers.size();
|
allocateInfo.commandBufferCount = commandBuffers.size();
|
||||||
|
|
||||||
VK_ASSERT(vkAllocateCommandBuffers(instance->GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to initialize command buffer");
|
CP_VK_ASSERT(vkAllocateCommandBuffers(instance->GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to initialize command buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordCommandBuffer(VkCommandBuffer commandBuffer)
|
void RecordCommandBuffer(VkCommandBuffer commandBuffer)
|
||||||
@@ -383,10 +133,11 @@ private:
|
|||||||
beginInfo.flags = 0;
|
beginInfo.flags = 0;
|
||||||
beginInfo.pInheritanceInfo = nullptr;
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
|
|
||||||
VK_ASSERT(vkBeginCommandBuffer(commandBuffer, &beginInfo), "Failed to begin command buffer");
|
CP_VK_ASSERT(vkBeginCommandBuffer(commandBuffer, &beginInfo), "Failed to begin command buffer");
|
||||||
|
|
||||||
VkClearValue clearValue = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
VkClearValue clearValue = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||||
|
|
||||||
|
// TODO: framebuffer->Bind();
|
||||||
VkRenderPassBeginInfo renderPassBeginInfo{};
|
VkRenderPassBeginInfo renderPassBeginInfo{};
|
||||||
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
renderPassBeginInfo.renderPass = instance->GetSwapChain().GetRenderPass();
|
renderPassBeginInfo.renderPass = instance->GetSwapChain().GetRenderPass();
|
||||||
@@ -395,49 +146,34 @@ private:
|
|||||||
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
|
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
|
||||||
renderPassBeginInfo.clearValueCount = 1;
|
renderPassBeginInfo.clearValueCount = 1;
|
||||||
renderPassBeginInfo.pClearValues = &clearValue;
|
renderPassBeginInfo.pClearValues = &clearValue;
|
||||||
|
|
||||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
|
||||||
|
graphicsPipeline->Bind(commandBuffer);
|
||||||
|
|
||||||
UpdateUniformBuffer();
|
UpdateUniformBuffer();
|
||||||
|
|
||||||
VkBuffer vbo = vertexBuffer->GetHandle();
|
vertexBuffer->Bind(commandBuffer);
|
||||||
VkDeviceSize offset = 0;
|
indexBuffer->Bind(commandBuffer);
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vbo, &offset);
|
uniformBuffer->Bind(commandBuffer);
|
||||||
vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetHandle(), 0, VK_INDEX_TYPE_UINT16);
|
|
||||||
|
|
||||||
VkViewport viewport{};
|
indexBuffer->Draw(commandBuffer);
|
||||||
viewport.x = 0.0f;
|
|
||||||
viewport.y = 0.0f;
|
|
||||||
viewport.width = instance->GetSwapChain().GetExtent().width;
|
|
||||||
viewport.height = instance->GetSwapChain().GetExtent().height;
|
|
||||||
viewport.minDepth = 0.0f;
|
|
||||||
viewport.maxDepth = 1.0f;
|
|
||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
|
||||||
VkRect2D scissor{};
|
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = instance->GetSwapChain().GetExtent();
|
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[instance->GetSwapChain().GetFlightIndex()], 0, nullptr);
|
|
||||||
vkCmdDrawIndexed(commandBuffer, indices.size(), 1, 0, 0, 0);
|
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
VK_ASSERT(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer");
|
CP_VK_ASSERT(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateUniformBuffer()
|
void UpdateUniformBuffer()
|
||||||
{
|
{
|
||||||
static auto startTime = std::chrono::high_resolution_clock::now();
|
static Timer startTimer;
|
||||||
|
|
||||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
float time = startTimer.Elapsed();
|
||||||
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
|
ShaderUniform shaderUniform;
|
||||||
uniformBufferObject.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
shaderUniform.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
uniformBufferObject.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
shaderUniform.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
uniformBufferObject.projection = glm::perspective(glm::radians(45.0f), instance->GetSwapChain().GetExtent().width / (float) instance->GetSwapChain().GetExtent().height, 0.1f, 10.0f);
|
shaderUniform.projection = glm::perspective(glm::radians(45.0f), instance->GetSwapChain().GetExtent().width / (float) instance->GetSwapChain().GetExtent().height, 0.1f, 10.0f);
|
||||||
uniformBufferObject.projection[1][1] *= -1;
|
shaderUniform.projection[1][1] *= -1;
|
||||||
|
|
||||||
uniformBuffer->Update(&uniformBufferObject, instance->GetSwapChain().GetFlightIndex());
|
uniformBuffer->Update(shaderUniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
|
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
|
||||||
@@ -448,7 +184,7 @@ private:
|
|||||||
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
||||||
|
|
||||||
VkShaderModule shaderModule;
|
VkShaderModule shaderModule;
|
||||||
VK_ASSERT(vkCreateShaderModule(instance->GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
|
CP_VK_ASSERT(vkCreateShaderModule(instance->GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
|
||||||
|
|
||||||
return shaderModule;
|
return shaderModule;
|
||||||
}
|
}
|
||||||
@@ -456,13 +192,21 @@ private:
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
glfwInit();
|
CP_ASSERT(glfwInit() == GLFW_TRUE, "Failed to initialize the glfw context");
|
||||||
|
|
||||||
{
|
{
|
||||||
Application application;
|
Application application;
|
||||||
|
Timer timer;
|
||||||
|
int frames = 0;
|
||||||
while (application.Update())
|
while (application.Update())
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
if (timer.Elapsed() >= 1.0)
|
||||||
|
{
|
||||||
|
std::cout << frames << "fps" << std::endl;
|
||||||
|
frames = 0;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
frames++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user