Add depth buffer
- Add depth testing to swapchain - Add Shader abstraction - Add CommandBuffer abstraction
This commit is contained in:
@@ -123,7 +123,7 @@
|
|||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalLibraryDirectories>$(ProjectDir)ext/lib/;C:/VulkanSDK/1.3.236.0/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(ProjectDir)ext/lib/;C:/VulkanSDK/1.3.236.0/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;shaderc_combinedd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
<PreBuildEvent>
|
<PreBuildEvent>
|
||||||
<Command>
|
<Command>
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalLibraryDirectories>$(ProjectDir)ext/lib/;C:/VulkanSDK/1.3.236.0/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(ProjectDir)ext/lib/;C:/VulkanSDK/1.3.236.0/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;shaderc_combinedd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
<PreBuildEvent>
|
<PreBuildEvent>
|
||||||
<Command>
|
<Command>
|
||||||
@@ -166,15 +166,19 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\Buffer.h" />
|
<ClInclude Include="src\Buffer.h" />
|
||||||
|
<ClInclude Include="src\CommandBuffer.h" />
|
||||||
<ClInclude Include="src\Common.h" />
|
<ClInclude Include="src\Common.h" />
|
||||||
<ClInclude Include="src\DebugMessenger.h" />
|
<ClInclude Include="src\DebugMessenger.h" />
|
||||||
<ClInclude Include="src\DescriptorSet.h" />
|
<ClInclude Include="src\DescriptorSet.h" />
|
||||||
<ClInclude Include="src\DescriptorPool.h" />
|
<ClInclude Include="src\DescriptorPool.h" />
|
||||||
<ClInclude Include="src\FileSystem.h" />
|
<ClInclude Include="src\FileSystem.h" />
|
||||||
|
<ClInclude Include="src\Image.h" />
|
||||||
<ClInclude Include="src\IndexBuffer.h" />
|
<ClInclude Include="src\IndexBuffer.h" />
|
||||||
<ClInclude Include="src\Pipeline.h" />
|
<ClInclude Include="src\Pipeline.h" />
|
||||||
<ClInclude Include="src\PipelineCreator.h" />
|
<ClInclude Include="src\PipelineCreator.h" />
|
||||||
<ClInclude Include="src\Sampler.h" />
|
<ClInclude Include="src\Shader.h" />
|
||||||
|
<ClInclude Include="src\Texture2D.h" />
|
||||||
|
<ClInclude Include="src\CommandBufferScoped.h" />
|
||||||
<ClInclude Include="src\UniformBuffer.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" />
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
<ClInclude Include="src\VertexDescriptor.h">
|
<ClInclude Include="src\VertexDescriptor.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\Sampler.h">
|
<ClInclude Include="src\Texture2D.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\DescriptorSet.h">
|
<ClInclude Include="src\DescriptorSet.h">
|
||||||
@@ -83,6 +83,18 @@
|
|||||||
<ClInclude Include="src\DescriptorPool.h">
|
<ClInclude Include="src\DescriptorPool.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\CommandBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\CommandBufferScoped.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Shader.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Image.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="res\shaders\shader.frag" />
|
<None Include="res\shaders\shader.frag" />
|
||||||
|
|||||||
Binary file not shown.
@@ -1,12 +1,15 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(set = 1, binding = 0) uniform sampler2D texSampler;
|
layout(set = 0, binding = 1) uniform sampler2D texSampler;
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
layout(location = 0) in vec3 fragColor;
|
||||||
layout(location = 1) in vec2 fragTexCoord;
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
|
layout(location = 2) in vec3 fragPosition;
|
||||||
|
layout(location = 3) in vec3 fragLightPos;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord);
|
float scale = 0.45 + max(dot(vec3(0, 1, 0), normalize(fragLightPos - fragPosition)), 0.0);
|
||||||
|
outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord) * scale;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,19 @@ layout(set = 0, binding = 0) uniform SceneUniformBufferObject
|
|||||||
vec3 lightPos;
|
vec3 lightPos;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inColor;
|
layout(location = 1) in vec3 inColor;
|
||||||
layout(location = 2) in vec2 inTexCoord;
|
layout(location = 2) in vec2 inTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
layout(location = 1) out vec2 fragTexCoord;
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
layout(location = 2) out vec3 fragPosition;
|
||||||
|
layout(location = 3) out vec3 fragLightPos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition.x, 0.0, inPosition.y, 1.0);
|
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
||||||
fragColor = inColor;
|
fragColor = inColor;
|
||||||
fragTexCoord = inTexCoord;
|
fragTexCoord = inTexCoord;
|
||||||
|
fragPosition = vec3(ubo.model * vec4(inPosition, 1.0));
|
||||||
|
fragLightPos = ubo.lightPos;
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
enum class CommandBufferType
|
||||||
|
{
|
||||||
|
SingleUse, Dynamic
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandBuffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBuffer);
|
||||||
|
private:
|
||||||
|
Instance& instance;
|
||||||
|
|
||||||
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
|
const CommandBufferType type;
|
||||||
|
VkCommandBuffer currentCommandBuffer{VK_NULL_HANDLE};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CommandBuffer(Instance& instance, CommandBufferType type)
|
||||||
|
: instance{instance}, type{type}
|
||||||
|
{
|
||||||
|
if (type == CommandBufferType::Dynamic)
|
||||||
|
commandBuffers.resize(instance.GetMaxFramesInFlight());
|
||||||
|
else
|
||||||
|
commandBuffers.resize(1);
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo allocateInfo{};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocateInfo.commandPool = instance.GetCommandPool();
|
||||||
|
allocateInfo.commandBufferCount = commandBuffers.size();
|
||||||
|
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to allocate CommandBuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
~CommandBuffer()
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test as constexpr function to see if it avoids the switch case
|
||||||
|
void Begin()
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo beginInfo{};
|
||||||
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
beginInfo.flags = 0;
|
||||||
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case CommandBufferType::SingleUse:
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
currentCommandBuffer = commandBuffers.front();
|
||||||
|
break;
|
||||||
|
case CommandBufferType::Dynamic:
|
||||||
|
currentCommandBuffer = commandBuffers[instance.GetFlightIndex()];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CP_WARN("Unhandled enum case: %d", (int)type);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkResetCommandBuffer(currentCommandBuffer, 0);
|
||||||
|
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Failed to begin command buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void End()
|
||||||
|
{
|
||||||
|
vkEndCommandBuffer(currentCommandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Submit()
|
||||||
|
{
|
||||||
|
VkSubmitInfo submitInfo{};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = ¤tCommandBuffer;
|
||||||
|
|
||||||
|
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
|
||||||
|
// TODO: if singleUse?
|
||||||
|
vkQueueWaitIdle(instance.GetGraphicsQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubmitAsGraphicsQueue()
|
||||||
|
{
|
||||||
|
instance.SubmitGraphicsQueue({currentCommandBuffer});
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBuffer GetHandle()
|
||||||
|
{
|
||||||
|
return currentCommandBuffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "CommandBuffer.h"
|
||||||
|
|
||||||
|
class CommandBufferScoped : public CommandBuffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBufferScoped);
|
||||||
|
public:
|
||||||
|
CommandBufferScoped(Instance& instance)
|
||||||
|
: CommandBuffer{instance, CommandBufferType::SingleUse}
|
||||||
|
{
|
||||||
|
CommandBuffer::Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
~CommandBufferScoped()
|
||||||
|
{
|
||||||
|
CommandBuffer::End();
|
||||||
|
CommandBuffer::Submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
+33
-26
@@ -1,43 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "VulkanException.h"
|
#include "VulkanException.h"
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define CP_DEBUG(format, ...) std::cout << "[DBG] " << StringFormat(format, __VA_ARGS__) << std::endl
|
#define TERM_RED "\x1B[31m"
|
||||||
|
#define TERM_GREEN "\x1B[32m"
|
||||||
|
#define TERM_YELLOW "\x1B[33m"
|
||||||
|
#define TERM_GRAY "\x1B[90m"
|
||||||
|
#define TERM_CLEAR "\033[0m"
|
||||||
|
|
||||||
|
#define CP_DEBUG(format, ...) std::cout << TERM_GRAY << "[DBG] " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
#define CP_INFO(format, ...) std::cout << "[INF] " << StringFormat(format, __VA_ARGS__) << std::endl
|
#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_WARN(format, ...) std::cout << TERM_YELLOW << "[WRN] " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
#define CP_ERR(format, ...) std::cout << "[ERR] " << StringFormat(format, __VA_ARGS__) << std::endl
|
#define CP_ERR(format, ...) std::cout << TERM_RED << "[ERR] " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
|
|
||||||
|
// Continue traces, will not print the [XXX] tag before the log
|
||||||
|
#define CP_DEBUG_CONT(format, ...) std::cout << TERM_GRAY << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
|
#define CP_INFO_CONT(format, ...) std::cout << " " << StringFormat(format, __VA_ARGS__) << std::endl
|
||||||
|
#define CP_WARN_CONT(format, ...) std::cout << TERM_YELLOW << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
|
#define CP_ERR_CONT(format, ...) std::cout << TERM_RED << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
|
|
||||||
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
|
#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_ASSERT(Function, format, ...) \
|
||||||
#define CP_VK_ASSERT(Function, format, ...) if(Function != VK_SUCCESS) { throw VulkanException(StringFormat(format, __VA_ARGS__)); } while(false)
|
do \
|
||||||
|
{ \
|
||||||
|
if(!(Function)) \
|
||||||
|
{ \
|
||||||
|
CP_ERR(format, __VA_ARGS__); \
|
||||||
|
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
|
||||||
|
} \
|
||||||
|
} while(false)
|
||||||
|
#define CP_VK_ASSERT(Function, format, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if(Function != VK_SUCCESS) \
|
||||||
|
{ \
|
||||||
|
CP_ERR(format, __VA_ARGS__); \
|
||||||
|
throw VulkanException(StringFormat(format, __VA_ARGS__)); \
|
||||||
|
} \
|
||||||
|
} while(false)
|
||||||
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
||||||
ClassName(ClassName&&) = delete; \
|
ClassName(ClassName&&) = delete; \
|
||||||
ClassName(const ClassName&) = delete; \
|
ClassName(const ClassName&) = delete; \
|
||||||
ClassName& operator=(ClassName&&) = delete; \
|
ClassName& operator=(ClassName&&) = delete; \
|
||||||
ClassName& operator=(const ClassName&) = delete
|
ClassName& operator=(const ClassName&) = delete
|
||||||
|
|
||||||
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
|
||||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
|
||||||
const VkAllocationCallbacks* pAllocator,
|
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
|
||||||
{
|
|
||||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
|
||||||
if (func != nullptr)
|
|
||||||
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
|
||||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
|
||||||
VkDebugUtilsMessengerEXT debugMessenger,
|
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
|
||||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
||||||
if (func != nullptr) {
|
|
||||||
func(instance, debugMessenger, pAllocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
std::string StringFormat(const std::string& format, Args... args)
|
std::string StringFormat(const std::string& format, Args... args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,11 +56,33 @@ private:
|
|||||||
{
|
{
|
||||||
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||||
{
|
{
|
||||||
std::cerr << pCallbackData->pMessage << std::endl;
|
|
||||||
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||||
|
{
|
||||||
|
CP_ERR(pCallbackData->pMessage);
|
||||||
throw VulkanException(pCallbackData->pMessage);
|
throw VulkanException(pCallbackData->pMessage);
|
||||||
}
|
}
|
||||||
|
CP_WARN(pCallbackData->pMessage);
|
||||||
|
}
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
||||||
|
{
|
||||||
|
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr)
|
||||||
|
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
|
VkDebugUtilsMessengerEXT debugMessenger,
|
||||||
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
|
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr) {
|
||||||
|
func(instance, debugMessenger, pAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
createInfo.poolSizeCount = poolSizes.size();
|
createInfo.poolSizeCount = poolSizes.size();
|
||||||
createInfo.pPoolSizes = poolSizes.data();
|
createInfo.pPoolSizes = poolSizes.data();
|
||||||
createInfo.maxSets = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight();
|
createInfo.maxSets = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight();
|
||||||
|
createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
|
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
|
||||||
}
|
}
|
||||||
@@ -52,4 +53,9 @@ public:
|
|||||||
|
|
||||||
return descriptorSets;
|
return descriptorSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
|
||||||
|
{
|
||||||
|
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DescriptorPool.h"
|
#include "DescriptorPool.h"
|
||||||
#include "Sampler.h"
|
#include "Texture2D.h"
|
||||||
#include "UniformBuffer.h"
|
#include "UniformBuffer.h"
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
class DescriptorSet
|
class DescriptorSet final
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
|
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
|
||||||
private:
|
private:
|
||||||
@@ -23,6 +23,11 @@ public:
|
|||||||
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
|
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~DescriptorSet()
|
||||||
|
{
|
||||||
|
descriptorPool.FreeDescriptorSets(descriptorSets);
|
||||||
|
}
|
||||||
|
|
||||||
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
|
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
||||||
@@ -42,9 +47,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSampler(const Sampler& sampler, uint32_t binding)
|
void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
|
||||||
{
|
{
|
||||||
VkDescriptorImageInfo imageInfo = sampler.GetDescriptorImageInfo();
|
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo();
|
||||||
for (auto&& descriptorSet : descriptorSets) {
|
for (auto&& descriptorSet : descriptorSets) {
|
||||||
VkWriteDescriptorSet descriptorWrite{};
|
VkWriteDescriptorSet descriptorWrite{};
|
||||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -19,4 +22,48 @@ namespace FileSystem
|
|||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string ReadFileStr(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "Failed to open file");
|
||||||
|
|
||||||
|
size_t fileSize = (size_t) file.tellg();
|
||||||
|
std::string buffer;
|
||||||
|
buffer.resize(fileSize);
|
||||||
|
|
||||||
|
file.seekg(0);
|
||||||
|
file.read(buffer.data(), fileSize);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteFile(const std::string& filename, const std::string& data)
|
||||||
|
{
|
||||||
|
std::ofstream file(filename, std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "Failed to open file");
|
||||||
|
|
||||||
|
file.write(data.c_str(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteFile(const std::string& filename, const char* data, size_t size)
|
||||||
|
{
|
||||||
|
std::ofstream file(filename, std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "Failed to open file");
|
||||||
|
|
||||||
|
file.write(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FileExists(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename);
|
||||||
|
return file.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t DateModified(const std::string& filename)
|
||||||
|
{
|
||||||
|
struct stat result;
|
||||||
|
CP_ASSERT(stat(filename.c_str(), &result) == 0, "Cannot stat file %s", filename.c_str());
|
||||||
|
return (int64_t)result.st_mtime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "CommandBufferScoped.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
|
||||||
|
class Image
|
||||||
|
{
|
||||||
|
Image() = delete;
|
||||||
|
public:
|
||||||
|
static void InitializeImage(Instance& instance, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* imageMemory)
|
||||||
|
{
|
||||||
|
VkImageCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
createInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
createInfo.extent.width = width;
|
||||||
|
createInfo.extent.height = height;
|
||||||
|
createInfo.extent.depth = 1;
|
||||||
|
createInfo.mipLevels = 1;
|
||||||
|
createInfo.arrayLayers = 1;
|
||||||
|
createInfo.format = format;
|
||||||
|
createInfo.tiling = tiling;
|
||||||
|
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
createInfo.usage = usage;
|
||||||
|
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
createInfo.flags = 0;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "Failed to initialize image");
|
||||||
|
|
||||||
|
VkMemoryRequirements memoryRequirements;
|
||||||
|
vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocateInfo{};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
|
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, imageMemory), "Failed to initiallizse image memory");
|
||||||
|
|
||||||
|
vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VkImageView InitializeImageView(Instance& instance, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
|
||||||
|
{
|
||||||
|
VkImageView imageView;
|
||||||
|
VkImageViewCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = image;
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = format;
|
||||||
|
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 = aspectFlags;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize image view");
|
||||||
|
return imageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TransitionImageLayout(Instance& instance, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout)
|
||||||
|
{
|
||||||
|
CommandBufferScoped commandBuffer{instance};
|
||||||
|
|
||||||
|
VkImageMemoryBarrier barrier{};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.oldLayout = oldLayout;
|
||||||
|
barrier.newLayout = newLayout;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = image;
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = 1;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = 0;
|
||||||
|
|
||||||
|
VkPipelineStageFlags srcStage;
|
||||||
|
VkPipelineStageFlags dstStage;
|
||||||
|
|
||||||
|
if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||||
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
|
||||||
|
if (HasStencilComponent(format)) {
|
||||||
|
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
}
|
||||||
|
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Unsupported layout transition");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer.GetHandle(), srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
CommandBufferScoped commandBuffer{instance};
|
||||||
|
|
||||||
|
VkBufferImageCopy region{};
|
||||||
|
region.bufferOffset = 0;
|
||||||
|
region.bufferRowLength = 0;
|
||||||
|
region.bufferImageHeight = 0;
|
||||||
|
|
||||||
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
region.imageSubresource.mipLevel = 0;
|
||||||
|
region.imageSubresource.baseArrayLayer = 0;
|
||||||
|
region.imageSubresource.layerCount = 1;
|
||||||
|
|
||||||
|
region.imageOffset = {0, 0, 0};
|
||||||
|
region.imageExtent = {width, height, 1};
|
||||||
|
|
||||||
|
vkCmdCopyBufferToImage(commandBuffer.GetHandle(), buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool HasStencilComponent(VkFormat format)
|
||||||
|
{
|
||||||
|
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -48,10 +48,10 @@ public:
|
|||||||
InitializeSurface();
|
InitializeSurface();
|
||||||
SelectPhysicalDevice();
|
SelectPhysicalDevice();
|
||||||
InitializeLogicalDevice();
|
InitializeLogicalDevice();
|
||||||
InitializeSwapChain();
|
|
||||||
InitializeCommandPool();
|
InitializeCommandPool();
|
||||||
|
InitializeSwapChain();
|
||||||
InitializeSyncObjects();
|
InitializeSyncObjects();
|
||||||
std::cout << "Initialized Vulkan in " << timer.Elapsed() << " seconds" << std::endl;
|
CP_INFO("Initialized Vulkan in %f seconds", timer.Elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
~Instance()
|
~Instance()
|
||||||
@@ -211,10 +211,10 @@ private:
|
|||||||
std::vector<VkExtensionProperties> extensions{extensionCount};
|
std::vector<VkExtensionProperties> extensions{extensionCount};
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||||
|
|
||||||
std::cout << "Supported Extensions: " << std::endl;
|
CP_INFO("Supported Extensions:");
|
||||||
for (auto&& extension : extensions)
|
for (auto&& extension : extensions)
|
||||||
{
|
{
|
||||||
std::cout << "\t" << extension.extensionName << std::endl;
|
CP_INFO_CONT("\t%s", extension.extensionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> layers{};
|
std::vector<const char*> layers{};
|
||||||
@@ -249,12 +249,12 @@ private:
|
|||||||
|
|
||||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||||
std::cout << "Available devices: " << std::endl;
|
CP_INFO("Available devices:");
|
||||||
for (auto&& device : devices)
|
for (auto&& device : devices)
|
||||||
{
|
{
|
||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||||
std::cout << "\t" << deviceProperties.deviceName << std::endl;
|
CP_INFO_CONT("\t%s", deviceProperties.deviceName);
|
||||||
}
|
}
|
||||||
for (auto&& device : devices)
|
for (auto&& device : devices)
|
||||||
{
|
{
|
||||||
@@ -263,7 +263,7 @@ private:
|
|||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||||
physicalDevice = device;
|
physicalDevice = device;
|
||||||
std::cout << "Selecting device: " << deviceProperties.deviceName << std::endl;
|
CP_INFO("Selecting device: %s", deviceProperties.deviceName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,10 +362,10 @@ private:
|
|||||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||||
|
|
||||||
std::cout << "Supported Layers: " << std::endl;
|
CP_INFO("Supported Layers:");
|
||||||
for (auto&& availableLayer : availableLayers)
|
for (auto&& availableLayer : availableLayers)
|
||||||
{
|
{
|
||||||
std::cout << "\t" << availableLayer.layerName << std::endl;
|
CP_INFO_CONT("\t%s", availableLayer.layerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto&& layer : layers)
|
for (auto&& layer : layers)
|
||||||
|
|||||||
+44
-35
@@ -3,7 +3,9 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "DescriptorSet.h"
|
||||||
#include "PipelineCreator.h"
|
#include "PipelineCreator.h"
|
||||||
|
#include "Shader.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -16,6 +18,7 @@ private:
|
|||||||
Instance& instance;
|
Instance& instance;
|
||||||
|
|
||||||
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
|
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
|
||||||
|
std::vector<VkDescriptorSet> boundDescriptorSets;
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkPipeline graphicsPipeline;
|
VkPipeline graphicsPipeline;
|
||||||
|
|
||||||
@@ -55,9 +58,15 @@ public:
|
|||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipelineLayout GetPipelineLayout() const
|
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
|
||||||
{
|
{
|
||||||
return pipelineLayout;
|
CP_ASSERT(setIndex < boundDescriptorSets.size(), "DescriptorSet index is out of bounds");
|
||||||
|
boundDescriptorSets[setIndex] = descriptorSet.GetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindDescriptorSets(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, boundDescriptorSets.size(), boundDescriptorSets.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const
|
VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const
|
||||||
@@ -68,21 +77,27 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
|
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
|
||||||
{
|
{
|
||||||
|
boundDescriptorSets.resize(creator.descriptorSetLayouts.size());
|
||||||
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
|
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto&& binding : creator.descriptorSetLayouts)
|
for (auto&& bindings : creator.descriptorSetLayouts)
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
std::vector<VkDescriptorSetLayoutBinding> layoutBindings{bindings.second.size()};
|
||||||
layoutBinding.binding = 0;
|
int j = 0;
|
||||||
layoutBinding.descriptorType = binding.second.type;
|
for (auto&& binding : bindings.second)
|
||||||
layoutBinding.descriptorCount = 1;
|
{
|
||||||
layoutBinding.stageFlags = binding.second.flags;
|
layoutBindings[j].binding = binding.binding;
|
||||||
layoutBinding.pImmutableSamplers = nullptr;
|
layoutBindings[j].descriptorType = binding.type;
|
||||||
|
layoutBindings[j].descriptorCount = binding.count;
|
||||||
|
layoutBindings[j].stageFlags = binding.flags;
|
||||||
|
layoutBindings[j].pImmutableSamplers = nullptr;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo createInfo{};
|
VkDescriptorSetLayoutCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
createInfo.bindingCount = 1;
|
createInfo.bindingCount = layoutBindings.size();
|
||||||
createInfo.pBindings = &layoutBinding;
|
createInfo.pBindings = layoutBindings.data();
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayouts[i++]), "Failed to initialize descriptor set layout");
|
CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayouts[i++]), "Failed to initialize descriptor set layout");
|
||||||
}
|
}
|
||||||
@@ -90,24 +105,7 @@ private:
|
|||||||
|
|
||||||
void InitializePipeline(const PipelineCreator& creator)
|
void InitializePipeline(const PipelineCreator& creator)
|
||||||
{
|
{
|
||||||
std::vector<char> vertShaderCode = FileSystem::ReadFile(creator.vertexShader);
|
Shader shader{instance, ShaderType::GlslFile, creator.vertexShader, creator.fragmentShader};
|
||||||
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{};
|
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
|
||||||
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
@@ -173,6 +171,19 @@ private:
|
|||||||
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
|
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
|
||||||
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
|
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depthStencilCreateInfo{};
|
||||||
|
depthStencilCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
depthStencilCreateInfo.depthTestEnable = VK_TRUE;
|
||||||
|
depthStencilCreateInfo.depthWriteEnable = VK_TRUE;
|
||||||
|
depthStencilCreateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||||
|
depthStencilCreateInfo.depthBoundsTestEnable = VK_FALSE;
|
||||||
|
depthStencilCreateInfo.minDepthBounds = 0.0f;
|
||||||
|
depthStencilCreateInfo.maxDepthBounds = 1.0f;
|
||||||
|
depthStencilCreateInfo.stencilTestEnable = VK_FALSE;
|
||||||
|
depthStencilCreateInfo.front = {};
|
||||||
|
depthStencilCreateInfo.back = {};
|
||||||
|
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState colorBlendAttachment{}; // TODO: Add to PipelineCreator
|
VkPipelineColorBlendAttachmentState colorBlendAttachment{}; // TODO: Add to PipelineCreator
|
||||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||||
VK_COLOR_COMPONENT_G_BIT |
|
VK_COLOR_COMPONENT_G_BIT |
|
||||||
@@ -206,16 +217,17 @@ private:
|
|||||||
|
|
||||||
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
|
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout");
|
||||||
|
|
||||||
|
const std::vector<VkPipelineShaderStageCreateInfo>& shaderStages = shader.GetShaderStages();
|
||||||
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
|
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
|
||||||
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
graphicsPipelineCreateInfo.stageCount = 2;
|
graphicsPipelineCreateInfo.stageCount = shaderStages.size();
|
||||||
graphicsPipelineCreateInfo.pStages = shaderStages;
|
graphicsPipelineCreateInfo.pStages = shaderStages.data();
|
||||||
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
|
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
|
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
|
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
|
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
|
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pDepthStencilState = nullptr;
|
graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
||||||
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
||||||
@@ -225,9 +237,6 @@ private:
|
|||||||
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
|
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)
|
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <map>
|
||||||
|
|
||||||
class PipelineCreator
|
class PipelineCreator
|
||||||
{
|
{
|
||||||
struct DescriptorSetLayout
|
struct DescriptorSetBinding
|
||||||
{
|
{
|
||||||
|
uint32_t binding;
|
||||||
VkDescriptorType type;
|
VkDescriptorType type;
|
||||||
|
uint32_t count;
|
||||||
VkShaderStageFlags flags;
|
VkShaderStageFlags flags;
|
||||||
};
|
};
|
||||||
friend class Pipeline;
|
friend class Pipeline;
|
||||||
private:
|
private:
|
||||||
std::map<uint32_t, DescriptorSetLayout> descriptorSetLayouts{};
|
std::map<uint32_t, std::vector<DescriptorSetBinding>> descriptorSetLayouts{};
|
||||||
|
|
||||||
std::string vertexShader;
|
std::string vertexShader;
|
||||||
std::string fragmentShader;
|
std::string fragmentShader;
|
||||||
@@ -22,7 +26,6 @@ private:
|
|||||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader)
|
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader)
|
||||||
: vertexShader{vertexShader}, fragmentShader{fragmentShader}
|
: vertexShader{vertexShader}, fragmentShader{fragmentShader}
|
||||||
@@ -33,9 +36,10 @@ public:
|
|||||||
vertexDescriptor = descriptor;
|
vertexDescriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddDescriptorSetLayoutBinding(uint32_t set, VkDescriptorType type, VkShaderStageFlags stageFlags)
|
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
|
||||||
{
|
{
|
||||||
descriptorSetLayouts.emplace(set, DescriptorSetLayout{type, stageFlags});
|
CP_ASSERT(set <= descriptorSetLayouts.size(), "Cannot add descriptor set with set number greater than the current set count");
|
||||||
|
descriptorSetLayouts[set].emplace_back(DescriptorSetBinding{binding, type, count, stageFlags});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Instance.h"
|
|
||||||
#include "Pipeline.h"
|
|
||||||
|
|
||||||
class Sampler
|
|
||||||
{
|
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Sampler);
|
|
||||||
private:
|
|
||||||
Instance& instance;
|
|
||||||
VkImageView imageView;
|
|
||||||
|
|
||||||
VkSampler textureSampler;
|
|
||||||
public:
|
|
||||||
Sampler(Instance& instance, VkImageView imageView)
|
|
||||||
: instance{instance}, imageView{imageView}
|
|
||||||
{
|
|
||||||
InitializeSampler(imageView);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Sampler()
|
|
||||||
{
|
|
||||||
vkDestroySampler(instance.GetDevice(), textureSampler, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorImageInfo GetDescriptorImageInfo() const
|
|
||||||
{
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.imageView = imageView;
|
|
||||||
imageInfo.sampler = textureSampler;
|
|
||||||
|
|
||||||
return imageInfo;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void InitializeSampler(VkImageView imageView)
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
|
||||||
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
|
|
||||||
|
|
||||||
VkSamplerCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
createInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
createInfo.anisotropyEnable = VK_TRUE;
|
|
||||||
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
|
||||||
createInfo.unnormalizedCoordinates = VK_FALSE;
|
|
||||||
createInfo.compareEnable = VK_FALSE;
|
|
||||||
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
createInfo.mipLodBias = 0.0f;
|
|
||||||
createInfo.minLod = 0.0f;
|
|
||||||
createInfo.maxLod = 0.0f;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &textureSampler), "Failed to initialize texture sampler");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <shaderc/shaderc.hpp>
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
|
||||||
|
enum class ShaderType
|
||||||
|
{
|
||||||
|
GlslFile, GlslCode, SpvFile, SpvCode
|
||||||
|
};
|
||||||
|
|
||||||
|
class Shader
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Shader);
|
||||||
|
private:
|
||||||
|
Instance& instance;
|
||||||
|
|
||||||
|
VkShaderModule vertShaderModule;
|
||||||
|
VkShaderModule fragShaderModule;
|
||||||
|
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||||
|
public:
|
||||||
|
Shader(Instance& instance, ShaderType shaderType, const std::string& vertexInput, const std::string& fragmentInput)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
switch (shaderType)
|
||||||
|
{
|
||||||
|
case ShaderType::GlslCode:
|
||||||
|
vertShaderModule = InitializeShaderModuleFromGlslCode(vertexInput, shaderc_vertex_shader);
|
||||||
|
fragShaderModule = InitializeShaderModuleFromGlslCode(fragmentInput, shaderc_fragment_shader);
|
||||||
|
break;
|
||||||
|
case ShaderType::GlslFile:
|
||||||
|
vertShaderModule = InitializeShaderModuleFromGlslFile(vertexInput, shaderc_vertex_shader);
|
||||||
|
fragShaderModule = InitializeShaderModuleFromGlslFile(fragmentInput, shaderc_fragment_shader);
|
||||||
|
break;
|
||||||
|
case ShaderType::SpvCode:
|
||||||
|
vertShaderModule = InitializeShaderModule(vertexInput);
|
||||||
|
fragShaderModule = InitializeShaderModule(fragmentInput);
|
||||||
|
break;
|
||||||
|
case ShaderType::SpvFile:
|
||||||
|
vertShaderModule = InitializeShaderModule(FileSystem::ReadFile(vertexInput));
|
||||||
|
fragShaderModule = InitializeShaderModule(FileSystem::ReadFile(fragmentInput));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CP_ASSERT(false, "Unreachable switch case %d", (int)shaderType);
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderStages.resize(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";
|
||||||
|
}
|
||||||
|
|
||||||
|
~Shader()
|
||||||
|
{
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), vertShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), fragShaderModule, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VkPipelineShaderStageCreateInfo> GetShaderStages() const
|
||||||
|
{
|
||||||
|
return shaderStages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkShaderModule InitializeShaderModule(const std::vector<uint32_t>& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(codeSpv.data(), codeSpv.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModule(const std::string& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(reinterpret_cast<const uint32_t*>(codeSpv.data()), codeSpv.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModule(const std::vector<char>& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(reinterpret_cast<const uint32_t*>(codeSpv.data()), codeSpv.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType)
|
||||||
|
{
|
||||||
|
std::string spvFilename = filename + ".spv";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (FileSystem::FileExists(spvFilename))
|
||||||
|
{
|
||||||
|
if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename))
|
||||||
|
{
|
||||||
|
CP_DEBUG("Loading cached shader file: %s", filename.c_str());
|
||||||
|
std::vector<char> data = FileSystem::ReadFile(spvFilename);
|
||||||
|
CP_ASSERT(data.size() % 4 == 0, "Spv data size is not a factor of 4");
|
||||||
|
return InitializeShaderModule((const uint32_t*)data.data(), data.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& e)
|
||||||
|
{
|
||||||
|
CP_WARN("Cached shader file is invalid, recreating it");
|
||||||
|
}
|
||||||
|
CP_DEBUG("Compiling shader file: %s", filename.c_str());
|
||||||
|
shaderc::Compiler compiler;
|
||||||
|
shaderc::CompileOptions options;
|
||||||
|
|
||||||
|
options.SetOptimizationLevel(shaderc_optimization_level_size);
|
||||||
|
|
||||||
|
std::vector<char> glslCode = FileSystem::ReadFile(filename);
|
||||||
|
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(glslCode.data(), glslCode.size(), shaderType, filename.c_str(), options);
|
||||||
|
CP_ASSERT(result.GetCompilationStatus() == shaderc_compilation_status_success, "Failed to compile shader: %s\n%s", filename.c_str(), result.GetErrorMessage().c_str());
|
||||||
|
|
||||||
|
std::vector<uint32_t> data{result.cbegin(), result.cend()};
|
||||||
|
FileSystem::WriteFile(spvFilename, (const char*)data.data(), data.size() * sizeof(uint32_t));
|
||||||
|
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModuleFromGlslCode(const std::string& code, shaderc_shader_kind shaderType)
|
||||||
|
{
|
||||||
|
shaderc::Compiler compiler;
|
||||||
|
shaderc::CompileOptions options;
|
||||||
|
|
||||||
|
options.SetOptimizationLevel(shaderc_optimization_level_size);
|
||||||
|
|
||||||
|
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(code.data(), shaderType, "inline_shader_code", options);
|
||||||
|
CP_ASSERT(result.GetCompilationStatus() == shaderc_compilation_status_success, "Failed to compile inline shader code: %s", result.GetErrorMessage());
|
||||||
|
|
||||||
|
std::vector<uint32_t> data{result.cbegin(), result.cend()};
|
||||||
|
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule InitializeShaderModule(const uint32_t* data, size_t size)
|
||||||
|
{
|
||||||
|
VkShaderModuleCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
createInfo.codeSize = size;
|
||||||
|
createInfo.pCode = data;
|
||||||
|
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
};
|
||||||
+67
-25
@@ -1,5 +1,9 @@
|
|||||||
#include "QueueFamilies.h"
|
#include "SwapChain.h"
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
#include "QueueFamilies.h"
|
||||||
|
|
||||||
#include <glfw/glfw3.h>
|
#include <glfw/glfw3.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -35,6 +39,7 @@ SwapChain::SwapChain(Instance& instance)
|
|||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
InitializeImageViews();
|
InitializeImageViews();
|
||||||
|
InitializeDepthBuffer();
|
||||||
InitializeRenderPass();
|
InitializeRenderPass();
|
||||||
InitializeFramebuffers();
|
InitializeFramebuffers();
|
||||||
}
|
}
|
||||||
@@ -111,6 +116,7 @@ void SwapChain::Recreate()
|
|||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
InitializeImageViews();
|
InitializeImageViews();
|
||||||
|
InitializeDepthBuffer();
|
||||||
InitializeFramebuffers();
|
InitializeFramebuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,24 +176,19 @@ void SwapChain::InitializeImageViews()
|
|||||||
imageViews.resize(images.size());
|
imageViews.resize(images.size());
|
||||||
for (size_t i = 0; i < images.size(); i++)
|
for (size_t i = 0; i < images.size(); i++)
|
||||||
{
|
{
|
||||||
VkImageViewCreateInfo createInfo{};
|
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
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::InitializeDepthBuffer()
|
||||||
|
{
|
||||||
|
VkFormat depthFormat = SelectDepthFormat();
|
||||||
|
Image::InitializeImage(instance, extent.width, extent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depthImage, &depthImageMemory);
|
||||||
|
Image::TransitionImageLayout(instance, depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
depthImageView = Image::InitializeImageView(instance, depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
void SwapChain::InitializeRenderPass()
|
void SwapChain::InitializeRenderPass()
|
||||||
{
|
{
|
||||||
VkAttachmentDescription colorAttachment{};
|
VkAttachmentDescription colorAttachment{};
|
||||||
@@ -200,28 +201,43 @@ void SwapChain::InitializeRenderPass()
|
|||||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
VkAttachmentDescription depthAttachment{};
|
||||||
|
depthAttachment.format = SelectDepthFormat();
|
||||||
|
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
VkAttachmentReference colorAttachmentRef{};
|
VkAttachmentReference colorAttachmentRef{};
|
||||||
colorAttachmentRef.attachment = 0;
|
colorAttachmentRef.attachment = 0;
|
||||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentReference depthAttachmentRef{};
|
||||||
|
depthAttachmentRef.attachment = 1;
|
||||||
|
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
VkSubpassDescription subpass{};
|
VkSubpassDescription subpass{};
|
||||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
subpass.colorAttachmentCount = 1;
|
subpass.colorAttachmentCount = 1;
|
||||||
subpass.pColorAttachments = &colorAttachmentRef;
|
subpass.pColorAttachments = &colorAttachmentRef;
|
||||||
|
subpass.pDepthStencilAttachment = &depthAttachmentRef;
|
||||||
|
|
||||||
VkSubpassDependency dependency{};
|
VkSubpassDependency dependency{};
|
||||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
dependency.dstSubpass = 0;
|
dependency.dstSubpass = 0;
|
||||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
dependency.srcAccessMask = 0;
|
dependency.srcAccessMask = 0;
|
||||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
||||||
|
|
||||||
|
std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment};
|
||||||
VkRenderPassCreateInfo renderPassCreateInfo{};
|
VkRenderPassCreateInfo renderPassCreateInfo{};
|
||||||
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
renderPassCreateInfo.attachmentCount = 1;
|
renderPassCreateInfo.attachmentCount = attachments.size();
|
||||||
renderPassCreateInfo.pAttachments = &colorAttachment;
|
renderPassCreateInfo.pAttachments = attachments.data();
|
||||||
renderPassCreateInfo.subpassCount = 1;
|
renderPassCreateInfo.subpassCount = 1;
|
||||||
renderPassCreateInfo.pSubpasses = &subpass;
|
renderPassCreateInfo.pSubpasses = &subpass;
|
||||||
renderPassCreateInfo.dependencyCount = 1;
|
renderPassCreateInfo.dependencyCount = 1;
|
||||||
@@ -236,13 +252,13 @@ void SwapChain::InitializeFramebuffers()
|
|||||||
|
|
||||||
for (size_t i = 0; i < imageViews.size(); ++i)
|
for (size_t i = 0; i < imageViews.size(); ++i)
|
||||||
{
|
{
|
||||||
VkImageView attachments[] = {imageViews[i]};
|
std::vector<VkImageView> attachments{imageViews[i], depthImageView};
|
||||||
|
|
||||||
VkFramebufferCreateInfo createInfo{};
|
VkFramebufferCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
createInfo.renderPass = renderPass;
|
createInfo.renderPass = renderPass;
|
||||||
createInfo.attachmentCount = 1;
|
createInfo.attachmentCount = attachments.size();
|
||||||
createInfo.pAttachments = attachments;
|
createInfo.pAttachments = attachments.data();
|
||||||
createInfo.width = extent.width;
|
createInfo.width = extent.width;
|
||||||
createInfo.height = extent.height;
|
createInfo.height = extent.height;
|
||||||
createInfo.layers = 1;
|
createInfo.layers = 1;
|
||||||
@@ -253,6 +269,9 @@ void SwapChain::InitializeFramebuffers()
|
|||||||
|
|
||||||
void SwapChain::Destroy()
|
void SwapChain::Destroy()
|
||||||
{
|
{
|
||||||
|
vkDestroyImage(instance.GetDevice(), depthImage, nullptr);
|
||||||
|
vkFreeMemory(instance.GetDevice(), depthImageMemory, nullptr);
|
||||||
|
vkDestroyImageView(instance.GetDevice(), depthImageView, nullptr);
|
||||||
for (auto&& framebuffer : framebuffers)
|
for (auto&& framebuffer : framebuffers)
|
||||||
{
|
{
|
||||||
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
@@ -276,6 +295,29 @@ VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfac
|
|||||||
return availableFormats[0];
|
return availableFormats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkFormat SwapChain::SelectDepthFormat()
|
||||||
|
{
|
||||||
|
return SelectSupportedFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFormat SwapChain::SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
|
||||||
|
{
|
||||||
|
for (VkFormat format : candidates)
|
||||||
|
{
|
||||||
|
VkFormatProperties properties;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(instance.GetPhysicalDevice(), format, &properties);
|
||||||
|
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features)
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features)
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Failed to select supported format");
|
||||||
|
}
|
||||||
|
|
||||||
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
||||||
{
|
{
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
|
|
||||||
@@ -26,6 +29,9 @@ private:
|
|||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
VkFormat imageFormat;
|
VkFormat imageFormat;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
|
VkImage depthImage;
|
||||||
|
VkImageView depthImageView;
|
||||||
|
VkDeviceMemory depthImageMemory;
|
||||||
std::vector<VkImageView> imageViews;
|
std::vector<VkImageView> imageViews;
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
std::vector<VkFramebuffer> framebuffers;
|
std::vector<VkFramebuffer> framebuffers;
|
||||||
@@ -48,11 +54,14 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void InitializeImageViews();
|
void InitializeImageViews();
|
||||||
|
void InitializeDepthBuffer();
|
||||||
void InitializeRenderPass();
|
void InitializeRenderPass();
|
||||||
void InitializeFramebuffers();
|
void InitializeFramebuffers();
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||||
|
VkFormat SelectDepthFormat();
|
||||||
|
VkFormat SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||||
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
||||||
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
|
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include "CommandBufferScoped.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Image.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb/stb_image.h>
|
||||||
|
|
||||||
|
class Texture2D
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
|
||||||
|
private:
|
||||||
|
Instance& instance;
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VkDeviceMemory imageMemory;
|
||||||
|
VkImageView imageView;
|
||||||
|
VkSampler sampler;
|
||||||
|
public:
|
||||||
|
Texture2D(Instance& instance, const std::string& filename)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
InitializeTextureImage(filename);
|
||||||
|
InitializeSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Texture2D()
|
||||||
|
{
|
||||||
|
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
||||||
|
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
||||||
|
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
||||||
|
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo GetDescriptorImageInfo() const
|
||||||
|
{
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.imageView = imageView;
|
||||||
|
imageInfo.sampler = sampler;
|
||||||
|
|
||||||
|
return imageInfo;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void InitializeTextureImage(const std::string& filename)
|
||||||
|
{
|
||||||
|
int texWidth;
|
||||||
|
int texHeight;
|
||||||
|
int texChannels;
|
||||||
|
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
|
|
||||||
|
CP_ASSERT(pixels, "Failed to load texture image");
|
||||||
|
|
||||||
|
VkDeviceSize bufferSize = texWidth * texHeight * 4;
|
||||||
|
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
||||||
|
void* data = stagingBuffer.Map();
|
||||||
|
memcpy(data, pixels, bufferSize);
|
||||||
|
stagingBuffer.Unmap();
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
Image::InitializeImage(instance, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
||||||
|
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
Image::CopyBufferToImage(instance, stagingBuffer, image, texWidth, texHeight);
|
||||||
|
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
imageView = Image::InitializeImageView(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeSampler()
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceProperties properties{};
|
||||||
|
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
|
||||||
|
|
||||||
|
VkSamplerCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
createInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
createInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.anisotropyEnable = VK_TRUE;
|
||||||
|
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
||||||
|
createInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
createInfo.compareEnable = VK_FALSE;
|
||||||
|
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
createInfo.mipLodBias = 0.0f;
|
||||||
|
createInfo.minLod = 0.0f;
|
||||||
|
createInfo.maxLod = 0.0f;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "Failed to initialize texture sampler");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView CreateImageView(VkImage image)
|
||||||
|
{
|
||||||
|
VkImageView imageView;
|
||||||
|
VkImageViewCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = image;
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
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, &imageView), "Failed to initialize ImageView");
|
||||||
|
|
||||||
|
return imageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Pipeline.h"
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
class UniformBuffer : public Buffer
|
class UniformBuffer : public Buffer
|
||||||
@@ -21,11 +20,6 @@ public:
|
|||||||
Buffer::Update((void*)&t, instance.GetFlightIndex());
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
|
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
|
||||||
{
|
{
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
|||||||
+2
-2
@@ -5,14 +5,14 @@
|
|||||||
#include "VertexDescriptor.h"
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec2 pos;
|
glm::vec3 pos;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
glm::vec2 texCoord;
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
static VertexDescriptor GetDescriptor()
|
static VertexDescriptor GetDescriptor()
|
||||||
{
|
{
|
||||||
VertexDescriptor descriptor{};
|
VertexDescriptor descriptor{};
|
||||||
descriptor.AddAttribute<Vertex>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, pos));
|
descriptor.AddAttribute<Vertex>(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos));
|
||||||
descriptor.AddAttribute<Vertex>(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
|
descriptor.AddAttribute<Vertex>(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
|
||||||
descriptor.AddAttribute<Vertex>(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord));
|
descriptor.AddAttribute<Vertex>(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord));
|
||||||
return descriptor;
|
return descriptor;
|
||||||
|
|||||||
+59
-259
@@ -1,36 +1,38 @@
|
|||||||
#include "FileSystem.h"
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "IndexBuffer.h"
|
|
||||||
#include "VertexBuffer.h"
|
|
||||||
#include "Instance.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
#include "UniformBuffer.h"
|
|
||||||
#include "Sampler.h"
|
|
||||||
#include "Vertex.h"
|
|
||||||
#include "Pipeline.h"
|
|
||||||
#include "DescriptorPool.h"
|
#include "DescriptorPool.h"
|
||||||
#include "DescriptorSet.h"
|
#include "DescriptorSet.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include "IndexBuffer.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
#include "Pipeline.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "UniformBuffer.h"
|
||||||
|
#include "Vertex.h"
|
||||||
|
#include "VertexBuffer.h"
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <glm/glm.hpp>
|
#include <vector>
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include <stb/stb_image.h>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
const std::vector<Vertex> vertices = {
|
const std::vector<Vertex> vertices = {
|
||||||
Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
Vertex{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
Vertex{{ 0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
Vertex{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}
|
Vertex{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||||
|
Vertex{{-0.5f, 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||||
|
Vertex{{ 0.5f, 0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||||
|
Vertex{{ 0.5f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
|
Vertex{{-0.5f, 0.0f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<uint16_t> indices = {
|
const std::vector<uint16_t> indices = {
|
||||||
0, 1, 2, 2, 3, 0
|
0, 1, 2, 2, 3, 0,
|
||||||
|
4, 5, 6, 6, 7, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
struct alignas(64) ShaderUniform
|
struct alignas(64) ShaderUniform
|
||||||
@@ -46,40 +48,30 @@ class Application final
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<Instance> instance;
|
std::unique_ptr<Instance> instance;
|
||||||
std::unique_ptr<Pipeline> graphicsPipeline;
|
std::unique_ptr<Pipeline> graphicsPipeline;
|
||||||
|
std::unique_ptr<Texture2D> texture2D;
|
||||||
|
std::unique_ptr<UniformBuffer> shaderUniformBuffer;
|
||||||
|
std::unique_ptr<DescriptorPool> descriptorPool;
|
||||||
|
std::unique_ptr<DescriptorSet> descriptorSet;
|
||||||
std::unique_ptr<VertexBuffer> vertexBuffer;
|
std::unique_ptr<VertexBuffer> vertexBuffer;
|
||||||
std::unique_ptr<IndexBuffer> indexBuffer;
|
std::unique_ptr<IndexBuffer> indexBuffer;
|
||||||
std::unique_ptr<UniformBuffer> shaderUniformBuffer;
|
std::unique_ptr<CommandBuffer> commandBuffer;
|
||||||
std::unique_ptr<Sampler> sampler;
|
|
||||||
std::unique_ptr<DescriptorPool> descriptorPool;
|
|
||||||
std::unique_ptr<DescriptorSet> uniformDescriptorSet;
|
|
||||||
std::unique_ptr<DescriptorSet> samplerDescriptorSet;
|
|
||||||
std::vector<VkCommandBuffer> commandBuffers;
|
|
||||||
|
|
||||||
VkImage textureImage;
|
|
||||||
VkDeviceMemory textureImageMemory;
|
|
||||||
VkImageView textureImageView;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application()
|
Application()
|
||||||
{
|
{
|
||||||
InitializeInstance();
|
InitializeInstance();
|
||||||
InitializeGraphicsPipeline();
|
InitializeGraphicsPipeline();
|
||||||
InitializeTextureImage();
|
|
||||||
InitializeTextureImageView();
|
|
||||||
InitializeTextureSampler();
|
InitializeTextureSampler();
|
||||||
InitializeUniformBuffer();
|
InitializeUniformBuffer();
|
||||||
InitializeDescriptorSets();
|
InitializeDescriptorSets();
|
||||||
InitializeVertexBuffer();
|
InitializeVertexBuffer();
|
||||||
InitializeIndexBuffer();
|
InitializeIndexBuffer();
|
||||||
InitializeCommandBuffers();
|
InitializeCommandBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Application()
|
~Application()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(instance->GetDevice());
|
vkDeviceWaitIdle(instance->GetDevice());
|
||||||
vkDestroyImage(instance->GetDevice(), textureImage, nullptr);
|
|
||||||
vkFreeMemory(instance->GetDevice(), textureImageMemory, nullptr);
|
|
||||||
vkDestroyImageView(instance->GetDevice(), textureImageView, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application(Application&&) = delete;
|
Application(Application&&) = delete;
|
||||||
@@ -92,9 +84,9 @@ public:
|
|||||||
if (!instance->BeginPresent())
|
if (!instance->BeginPresent())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RecordCommandBuffer(commandBuffers[instance->GetFlightIndex()]);
|
RecordCommandBuffer();
|
||||||
|
commandBuffer->SubmitAsGraphicsQueue();
|
||||||
|
|
||||||
instance->SubmitGraphicsQueue(std::vector<VkCommandBuffer>{commandBuffers[instance->GetFlightIndex()]});
|
|
||||||
return instance->EndPresent();
|
return instance->EndPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,184 +97,9 @@ private:
|
|||||||
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeTextureImage()
|
|
||||||
{
|
|
||||||
int texWidth;
|
|
||||||
int texHeight;
|
|
||||||
int texChannels;
|
|
||||||
stbi_uc* pixels = stbi_load("res/textures/texture.png", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
CP_ASSERT(pixels, "Failed to load texture image");
|
|
||||||
|
|
||||||
VkDeviceSize bufferSize = texWidth * texHeight * 4;
|
|
||||||
Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
|
||||||
void* data = stagingBuffer.Map();
|
|
||||||
memcpy(data, pixels, bufferSize);
|
|
||||||
stagingBuffer.Unmap();
|
|
||||||
stbi_image_free(pixels);
|
|
||||||
|
|
||||||
VkImageCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
createInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
createInfo.extent.width = texWidth;
|
|
||||||
createInfo.extent.height = texHeight;
|
|
||||||
createInfo.extent.depth = 1;
|
|
||||||
createInfo.mipLevels = 1;
|
|
||||||
createInfo.arrayLayers = 1;
|
|
||||||
createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
createInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
createInfo.flags = 0;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateImage(instance->GetDevice(), &createInfo, nullptr, &textureImage), "Failed to initialize texture image");
|
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements;
|
|
||||||
vkGetImageMemoryRequirements(instance->GetDevice(), textureImage, &memoryRequirements);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo allocateInfo{};
|
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
|
||||||
allocateInfo.memoryTypeIndex = instance->FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkAllocateMemory(instance->GetDevice(), &allocateInfo, nullptr, &textureImageMemory), "Failed to initiallizse texture image memory");
|
|
||||||
|
|
||||||
vkBindImageMemory(instance->GetDevice(), textureImage, textureImageMemory, 0);
|
|
||||||
|
|
||||||
TransitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
CopyBufferToImage(stagingBuffer, textureImage, texWidth, texHeight);
|
|
||||||
TransitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeTextureImageView()
|
|
||||||
{
|
|
||||||
textureImageView = CreateImageView();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeTextureSampler()
|
void InitializeTextureSampler()
|
||||||
{
|
{
|
||||||
sampler = std::make_unique<Sampler>(*instance, textureImageView);
|
texture2D = std::make_unique<Texture2D>(*instance, "res/textures/texture.png");
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView CreateImageView()
|
|
||||||
{
|
|
||||||
VkImageView imageView;
|
|
||||||
VkImageViewCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
createInfo.image = textureImage;
|
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
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, &imageView), "Failed to initialize ImageView");
|
|
||||||
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout)
|
|
||||||
{
|
|
||||||
VkCommandBuffer commandBuffer = BeginSingleUseCommandBuffer();
|
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier{};
|
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
barrier.oldLayout = oldLayout;
|
|
||||||
barrier.newLayout = newLayout;
|
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
||||||
barrier.image = image;
|
|
||||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
barrier.subresourceRange.baseMipLevel = 0;
|
|
||||||
barrier.subresourceRange.levelCount = 1;
|
|
||||||
barrier.subresourceRange.baseArrayLayer = 0;
|
|
||||||
barrier.subresourceRange.layerCount = 1;
|
|
||||||
barrier.srcAccessMask = 0;
|
|
||||||
barrier.dstAccessMask = 0;
|
|
||||||
|
|
||||||
VkPipelineStageFlags srcStage;
|
|
||||||
VkPipelineStageFlags dstStage;
|
|
||||||
|
|
||||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
|
||||||
barrier.srcAccessMask = 0;
|
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
|
|
||||||
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
||||||
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
||||||
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
|
|
||||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
||||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
||||||
} else {
|
|
||||||
throw std::invalid_argument("Unsupported layout transition");
|
|
||||||
}
|
|
||||||
|
|
||||||
vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
||||||
|
|
||||||
EndSinglelUseCommandBuffer(commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CopyBufferToImage(const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
|
|
||||||
{
|
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = BeginSingleUseCommandBuffer();
|
|
||||||
|
|
||||||
VkBufferImageCopy region{};
|
|
||||||
region.bufferOffset = 0;
|
|
||||||
region.bufferRowLength = 0;
|
|
||||||
region.bufferImageHeight = 0;
|
|
||||||
|
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
region.imageSubresource.mipLevel = 0;
|
|
||||||
region.imageSubresource.baseArrayLayer = 0;
|
|
||||||
region.imageSubresource.layerCount = 1;
|
|
||||||
|
|
||||||
region.imageOffset = {0, 0, 0};
|
|
||||||
region.imageExtent = {width, height, 1};
|
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
||||||
|
|
||||||
EndSinglelUseCommandBuffer(commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer BeginSingleUseCommandBuffer()
|
|
||||||
{
|
|
||||||
VkCommandBufferAllocateInfo allocInfo{};
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
||||||
allocInfo.commandPool = instance->GetCommandPool();
|
|
||||||
allocInfo.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer;
|
|
||||||
vkAllocateCommandBuffers(instance->GetDevice(), &allocInfo, &commandBuffer);
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
|
|
||||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndSinglelUseCommandBuffer(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
vkEndCommandBuffer(commandBuffer);
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
vkQueueSubmit(instance->GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
|
|
||||||
vkQueueWaitIdle(instance->GetGraphicsQueue());
|
|
||||||
|
|
||||||
vkFreeCommandBuffers(instance->GetDevice(), instance->GetCommandPool(), 1, &commandBuffer);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeUniformBuffer()
|
void InitializeUniformBuffer()
|
||||||
@@ -294,18 +111,16 @@ private:
|
|||||||
{
|
{
|
||||||
descriptorPool = std::make_unique<DescriptorPool>(*instance);
|
descriptorPool = std::make_unique<DescriptorPool>(*instance);
|
||||||
|
|
||||||
uniformDescriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
|
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
|
||||||
uniformDescriptorSet->AddUniform(*shaderUniformBuffer, 0);
|
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
|
||||||
|
descriptorSet->AddTexture2D(*texture2D, 1);
|
||||||
samplerDescriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(1));
|
|
||||||
samplerDescriptorSet->AddSampler(*sampler, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeGraphicsPipeline()
|
void InitializeGraphicsPipeline()
|
||||||
{
|
{
|
||||||
PipelineCreator creator{"res/shaders/vert.spv", "res/shaders/frag.spv"};
|
PipelineCreator creator{"res/shaders/shader.vert", "res/shaders/shader.frag"};
|
||||||
creator.AddDescriptorSetLayoutBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
|
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
creator.AddDescriptorSetLayoutBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
|
creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
||||||
creator.SetCullMode(VK_CULL_MODE_NONE);
|
creator.SetCullMode(VK_CULL_MODE_NONE);
|
||||||
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
||||||
@@ -324,30 +139,17 @@ private:
|
|||||||
indexBuffer->UpdateStaging((void*)indices.data());
|
indexBuffer->UpdateStaging((void*)indices.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeCommandBuffers()
|
void InitializeCommandBuffer()
|
||||||
{
|
{
|
||||||
commandBuffers.resize(instance->GetMaxFramesInFlight());
|
commandBuffer = std::make_unique<CommandBuffer>(*instance, CommandBufferType::Dynamic);
|
||||||
VkCommandBufferAllocateInfo allocateInfo{};
|
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
allocateInfo.commandPool = instance->GetCommandPool();
|
|
||||||
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
||||||
allocateInfo.commandBufferCount = commandBuffers.size();
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkAllocateCommandBuffers(instance->GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to initialize command buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordCommandBuffer(VkCommandBuffer commandBuffer)
|
void RecordCommandBuffer()
|
||||||
{
|
{
|
||||||
vkResetCommandBuffer(commandBuffer, 0);
|
commandBuffer->Begin();
|
||||||
|
std::vector<VkClearValue> clearValues{2};
|
||||||
VkCommandBufferBeginInfo beginInfo{};
|
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
beginInfo.flags = 0;
|
|
||||||
beginInfo.pInheritanceInfo = nullptr;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkBeginCommandBuffer(commandBuffer, &beginInfo), "Failed to begin command buffer");
|
|
||||||
|
|
||||||
VkClearValue clearValue = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
|
||||||
|
|
||||||
// TODO: framebuffer->Bind();
|
// TODO: framebuffer->Bind();
|
||||||
VkRenderPassBeginInfo renderPassBeginInfo{};
|
VkRenderPassBeginInfo renderPassBeginInfo{};
|
||||||
@@ -356,27 +158,24 @@ private:
|
|||||||
renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
|
renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
|
||||||
renderPassBeginInfo.renderArea.offset = {0, 0};
|
renderPassBeginInfo.renderArea.offset = {0, 0};
|
||||||
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
|
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
|
||||||
renderPassBeginInfo.clearValueCount = 1;
|
renderPassBeginInfo.clearValueCount = clearValues.size();
|
||||||
renderPassBeginInfo.pClearValues = &clearValue;
|
renderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(commandBuffer->GetHandle(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
graphicsPipeline->Bind(commandBuffer);
|
graphicsPipeline->Bind(commandBuffer->GetHandle());
|
||||||
|
|
||||||
UpdateUniformBuffer();
|
UpdateUniformBuffer();
|
||||||
|
|
||||||
vertexBuffer->Bind(commandBuffer);
|
vertexBuffer->Bind(commandBuffer->GetHandle());
|
||||||
indexBuffer->Bind(commandBuffer);
|
indexBuffer->Bind(commandBuffer->GetHandle());
|
||||||
shaderUniformBuffer->Bind(commandBuffer);
|
|
||||||
|
|
||||||
std::vector<VkDescriptorSet> sets{uniformDescriptorSet->GetHandle(), samplerDescriptorSet->GetHandle()};
|
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
|
||||||
// Replace the two lines above with this somehow:
|
|
||||||
// graphicsPipeline->BindDescriptorSets(uniformDescriptorSet, samplerDescriptorSet);
|
|
||||||
|
|
||||||
indexBuffer->Draw(commandBuffer);
|
indexBuffer->Draw(commandBuffer->GetHandle());
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer->GetHandle());
|
||||||
CP_VK_ASSERT(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer");
|
commandBuffer->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateUniformBuffer()
|
void UpdateUniformBuffer()
|
||||||
@@ -386,9 +185,10 @@ private:
|
|||||||
float time = startTimer.Elapsed();
|
float time = startTimer.Elapsed();
|
||||||
ShaderUniform shaderUniform;
|
ShaderUniform shaderUniform;
|
||||||
shaderUniform.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.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, 1.0f, 0.0f));
|
||||||
shaderUniform.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);
|
||||||
shaderUniform.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
shaderUniform.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
shaderUniform.projection[1][1] *= -1;
|
shaderUniform.projection[1][1] *= -1;
|
||||||
|
shaderUniform.lightPos = glm::rotate(glm::mat4{1.0f}, time * glm::radians(45.0f), glm::vec3(0, 1, 0)) * glm::vec4{0.3, 0.1, 0, 1};
|
||||||
|
|
||||||
shaderUniformBuffer->Update(shaderUniform);
|
shaderUniformBuffer->Update(shaderUniform);
|
||||||
}
|
}
|
||||||
@@ -419,7 +219,7 @@ int main()
|
|||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
if (timer.Elapsed() >= 1.0)
|
if (timer.Elapsed() >= 1.0)
|
||||||
{
|
{
|
||||||
std::cout << frames << "fps" << std::endl;
|
CP_DEBUG("%d fps", frames);
|
||||||
frames = 0;
|
frames = 0;
|
||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user