Add depth buffer

- Add depth testing to swapchain
- Add Shader abstraction
- Add CommandBuffer abstraction
This commit is contained in:
Thraix
2023-01-29 23:22:17 +01:00
parent 87ed5739b3
commit 9de2ff594b
25 changed files with 927 additions and 488 deletions
+7 -3
View File
@@ -123,7 +123,7 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<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>
<PreBuildEvent>
<Command>
@@ -150,7 +150,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<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>
<PreBuildEvent>
<Command>
@@ -166,15 +166,19 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Buffer.h" />
<ClInclude Include="src\CommandBuffer.h" />
<ClInclude Include="src\Common.h" />
<ClInclude Include="src\DebugMessenger.h" />
<ClInclude Include="src\DescriptorSet.h" />
<ClInclude Include="src\DescriptorPool.h" />
<ClInclude Include="src\FileSystem.h" />
<ClInclude Include="src\Image.h" />
<ClInclude Include="src\IndexBuffer.h" />
<ClInclude Include="src\Pipeline.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\Instance.h" />
<ClInclude Include="src\QueueFamilies.h" />
+13 -1
View File
@@ -74,7 +74,7 @@
<ClInclude Include="src\VertexDescriptor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Sampler.h">
<ClInclude Include="src\Texture2D.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\DescriptorSet.h">
@@ -83,6 +83,18 @@
<ClInclude Include="src\DescriptorPool.h">
<Filter>Header Files</Filter>
</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>
<None Include="res\shaders\shader.frag" />
Binary file not shown.
+5 -2
View File
@@ -1,12 +1,15 @@
#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 = 1) in vec2 fragTexCoord;
layout(location = 2) in vec3 fragPosition;
layout(location = 3) in vec3 fragLightPos;
layout(location = 0) out vec4 outColor;
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;
}
+6 -2
View File
@@ -8,15 +8,19 @@ layout(set = 0, binding = 0) uniform SceneUniformBufferObject
vec3 lightPos;
} ubo;
layout(location = 0) in vec2 inPosition;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
layout(location = 2) out vec3 fragPosition;
layout(location = 3) out vec3 fragLightPos;
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;
fragTexCoord = inTexCoord;
fragPosition = vec3(ubo.model * vec4(inPosition, 1.0));
fragLightPos = ubo.lightPos;
}
Binary file not shown.
+94
View File
@@ -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 = &currentCommandBuffer;
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
// TODO: if singleUse?
vkQueueWaitIdle(instance.GetGraphicsQueue());
}
void SubmitAsGraphicsQueue()
{
instance.SubmitGraphicsQueue({currentCommandBuffer});
}
VkCommandBuffer GetHandle()
{
return currentCommandBuffer;
}
};
+21
View File
@@ -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
View File
@@ -1,43 +1,50 @@
#pragma once
#include "VulkanException.h"
#include <vulkan/vulkan.hpp>
#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_WARN(format, ...) std::cout << "[WRN] " << StringFormat(format, __VA_ARGS__) << std::endl
#define CP_ERR(format, ...) std::cout << "[ERR] " << 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 << 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_ASSERT(Function, format, ...) if(!(Function)) { throw std::runtime_error(StringFormat(format, __VA_ARGS__)); } while(false)
#define CP_VK_ASSERT(Function, format, ...) if(Function != VK_SUCCESS) { throw VulkanException(StringFormat(format, __VA_ARGS__)); } while(false)
#define CP_ASSERT(Function, format, ...) \
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) \
ClassName(ClassName&&) = delete; \
ClassName(const ClassName&) = delete; \
ClassName& operator=(ClassName&&) = delete; \
ClassName& operator=(const ClassName&) = delete
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const 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>
std::string StringFormat(const std::string& format, Args... args)
{
+23 -1
View File
@@ -56,11 +56,33 @@ private:
{
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{
std::cerr << pCallbackData->pMessage << std::endl;
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{
CP_ERR(pCallbackData->pMessage);
throw VulkanException(pCallbackData->pMessage);
}
CP_WARN(pCallbackData->pMessage);
}
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);
}
}
};
+6
View File
@@ -28,6 +28,7 @@ public:
createInfo.poolSizeCount = poolSizes.size();
createInfo.pPoolSizes = poolSizes.data();
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");
}
@@ -52,4 +53,9 @@ public:
return descriptorSets;
}
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
{
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
}
};
+9 -4
View File
@@ -2,11 +2,11 @@
#include "Common.h"
#include "DescriptorPool.h"
#include "Sampler.h"
#include "Texture2D.h"
#include "UniformBuffer.h"
#include <vulkan/vulkan.hpp>
class DescriptorSet
class DescriptorSet final
{
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
private:
@@ -23,6 +23,11 @@ public:
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
}
~DescriptorSet()
{
descriptorPool.FreeDescriptorSets(descriptorSets);
}
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
{
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) {
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+47
View File
@@ -1,5 +1,8 @@
#pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include "Common.h"
#include <fstream>
@@ -19,4 +22,48 @@ namespace FileSystem
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;
}
}
+151
View File
@@ -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, &region);
}
private:
static bool HasStencilComponent(VkFormat format)
{
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
};
+9 -9
View File
@@ -48,10 +48,10 @@ public:
InitializeSurface();
SelectPhysicalDevice();
InitializeLogicalDevice();
InitializeSwapChain();
InitializeCommandPool();
InitializeSwapChain();
InitializeSyncObjects();
std::cout << "Initialized Vulkan in " << timer.Elapsed() << " seconds" << std::endl;
CP_INFO("Initialized Vulkan in %f seconds", timer.Elapsed());
}
~Instance()
@@ -211,10 +211,10 @@ private:
std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
std::cout << "Supported Extensions: " << std::endl;
CP_INFO("Supported Extensions:");
for (auto&& extension : extensions)
{
std::cout << "\t" << extension.extensionName << std::endl;
CP_INFO_CONT("\t%s", extension.extensionName);
}
std::vector<const char*> layers{};
@@ -249,12 +249,12 @@ private:
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
std::cout << "Available devices: " << std::endl;
CP_INFO("Available devices:");
for (auto&& device : devices)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
std::cout << "\t" << deviceProperties.deviceName << std::endl;
CP_INFO_CONT("\t%s", deviceProperties.deviceName);
}
for (auto&& device : devices)
{
@@ -263,7 +263,7 @@ private:
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
physicalDevice = device;
std::cout << "Selecting device: " << deviceProperties.deviceName << std::endl;
CP_INFO("Selecting device: %s", deviceProperties.deviceName);
break;
}
}
@@ -362,10 +362,10 @@ private:
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
std::cout << "Supported Layers: " << std::endl;
CP_INFO("Supported Layers:");
for (auto&& availableLayer : availableLayers)
{
std::cout << "\t" << availableLayer.layerName << std::endl;
CP_INFO_CONT("\t%s", availableLayer.layerName);
}
for (auto&& layer : layers)
+44 -35
View File
@@ -3,7 +3,9 @@
#include "Common.h"
#include "Instance.h"
#include "FileSystem.h"
#include "DescriptorSet.h"
#include "PipelineCreator.h"
#include "Shader.h"
#include <vulkan/vulkan.hpp>
#include <map>
@@ -16,6 +18,7 @@ private:
Instance& instance;
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
std::vector<VkDescriptorSet> boundDescriptorSets;
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
@@ -55,9 +58,15 @@ public:
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
@@ -68,21 +77,27 @@ public:
private:
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
{
boundDescriptorSets.resize(creator.descriptorSetLayouts.size());
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
int i = 0;
for (auto&& binding : creator.descriptorSetLayouts)
for (auto&& bindings : creator.descriptorSetLayouts)
{
VkDescriptorSetLayoutBinding layoutBinding{};
layoutBinding.binding = 0;
layoutBinding.descriptorType = binding.second.type;
layoutBinding.descriptorCount = 1;
layoutBinding.stageFlags = binding.second.flags;
layoutBinding.pImmutableSamplers = nullptr;
std::vector<VkDescriptorSetLayoutBinding> layoutBindings{bindings.second.size()};
int j = 0;
for (auto&& binding : bindings.second)
{
layoutBindings[j].binding = binding.binding;
layoutBindings[j].descriptorType = binding.type;
layoutBindings[j].descriptorCount = binding.count;
layoutBindings[j].stageFlags = binding.flags;
layoutBindings[j].pImmutableSamplers = nullptr;
j++;
}
VkDescriptorSetLayoutCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
createInfo.bindingCount = 1;
createInfo.pBindings = &layoutBinding;
createInfo.bindingCount = layoutBindings.size();
createInfo.pBindings = layoutBindings.data();
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)
{
std::vector<char> vertShaderCode = FileSystem::ReadFile(creator.vertexShader);
std::vector<char> fragShaderCode = FileSystem::ReadFile(creator.fragmentShader);
VkShaderModule vertShaderModule = InitializeShaderModule(vertShaderCode);
VkShaderModule fragShaderModule = InitializeShaderModule(fragShaderCode);
VkPipelineShaderStageCreateInfo shaderStages[2];
shaderStages[0] = {};
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStages[0].module = vertShaderModule;
shaderStages[0].pName = "main";
shaderStages[1] = {};
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = fragShaderModule;
shaderStages[1].pName = "main";
Shader shader{instance, ShaderType::GlslFile, creator.vertexShader, creator.fragmentShader};
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@@ -173,6 +171,19 @@ private:
multisampleCreateInfo.alphaToCoverageEnable = 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
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_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");
const std::vector<VkPipelineShaderStageCreateInfo>& shaderStages = shader.GetShaderStages();
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
graphicsPipelineCreateInfo.stageCount = 2;
graphicsPipelineCreateInfo.pStages = shaderStages;
graphicsPipelineCreateInfo.stageCount = shaderStages.size();
graphicsPipelineCreateInfo.pStages = shaderStages.data();
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
graphicsPipelineCreateInfo.pDepthStencilState = nullptr;
graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilCreateInfo;
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = pipelineLayout;
@@ -225,9 +237,6 @@ private:
graphicsPipelineCreateInfo.basePipelineIndex = -1;
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
vkDestroyShaderModule(instance.GetDevice(), vertShaderModule, nullptr);
vkDestroyShaderModule(instance.GetDevice(), fragShaderModule, nullptr);
}
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
+10 -6
View File
@@ -1,19 +1,23 @@
#pragma once
#include "Common.h"
#include "VertexDescriptor.h"
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan.hpp>
#include <map>
class PipelineCreator
{
struct DescriptorSetLayout
struct DescriptorSetBinding
{
uint32_t binding;
VkDescriptorType type;
uint32_t count;
VkShaderStageFlags flags;
};
friend class Pipeline;
private:
std::map<uint32_t, DescriptorSetLayout> descriptorSetLayouts{};
std::map<uint32_t, std::vector<DescriptorSetBinding>> descriptorSetLayouts{};
std::string vertexShader;
std::string fragmentShader;
@@ -22,7 +26,6 @@ private:
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
public:
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader)
: vertexShader{vertexShader}, fragmentShader{fragmentShader}
@@ -33,9 +36,10 @@ public:
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)
-61
View File
@@ -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");
}
};
+151
View File
@@ -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
View File
@@ -1,5 +1,9 @@
#include "QueueFamilies.h"
#include "SwapChain.h"
#include "Image.h"
#include "Instance.h"
#include "QueueFamilies.h"
#include <glfw/glfw3.h>
#include <vulkan/vulkan.h>
#include <vector>
@@ -35,6 +39,7 @@ SwapChain::SwapChain(Instance& instance)
{
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
@@ -111,6 +116,7 @@ void SwapChain::Recreate()
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeFramebuffers();
}
@@ -170,24 +176,19 @@ void SwapChain::InitializeImageViews()
imageViews.resize(images.size());
for (size_t i = 0; i < images.size(); i++)
{
VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.image = images[i];
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = imageFormat;
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.baseMipLevel = 0;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageViews[i]), "Failed to initialize swapchain image view");
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
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()
{
VkAttachmentDescription colorAttachment{};
@@ -200,28 +201,43 @@ void SwapChain::InitializeRenderPass()
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
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{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef{};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment};
VkRenderPassCreateInfo renderPassCreateInfo{};
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.attachmentCount = 1;
renderPassCreateInfo.pAttachments = &colorAttachment;
renderPassCreateInfo.attachmentCount = attachments.size();
renderPassCreateInfo.pAttachments = attachments.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpass;
renderPassCreateInfo.dependencyCount = 1;
@@ -236,13 +252,13 @@ void SwapChain::InitializeFramebuffers()
for (size_t i = 0; i < imageViews.size(); ++i)
{
VkImageView attachments[] = {imageViews[i]};
std::vector<VkImageView> attachments{imageViews[i], depthImageView};
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = renderPass;
createInfo.attachmentCount = 1;
createInfo.pAttachments = attachments;
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = extent.width;
createInfo.height = extent.height;
createInfo.layers = 1;
@@ -253,6 +269,9 @@ void SwapChain::InitializeFramebuffers()
void SwapChain::Destroy()
{
vkDestroyImage(instance.GetDevice(), depthImage, nullptr);
vkFreeMemory(instance.GetDevice(), depthImageMemory, nullptr);
vkDestroyImageView(instance.GetDevice(), depthImageView, nullptr);
for (auto&& framebuffer : framebuffers)
{
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
@@ -276,6 +295,29 @@ VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfac
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)
{
return VK_PRESENT_MODE_FIFO_KHR;
+9
View File
@@ -1,7 +1,10 @@
#pragma once
#include "Common.h"
#include <vulkan/vulkan.h>
#include <vector>
#include <GLFW/glfw3.h>
class Instance;
@@ -26,6 +29,9 @@ private:
VkRenderPass renderPass;
VkFormat imageFormat;
VkExtent2D extent;
VkImage depthImage;
VkImageView depthImageView;
VkDeviceMemory depthImageMemory;
std::vector<VkImageView> imageViews;
std::vector<VkImage> images;
std::vector<VkFramebuffer> framebuffers;
@@ -48,11 +54,14 @@ public:
private:
void Initialize();
void InitializeImageViews();
void InitializeDepthBuffer();
void InitializeRenderPass();
void InitializeFramebuffers();
void Destroy();
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);
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
};
+115
View File
@@ -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;
}
};
-6
View File
@@ -2,7 +2,6 @@
#include "Common.h"
#include "Buffer.h"
#include "Pipeline.h"
#include <vulkan/vulkan.hpp>
class UniformBuffer : public Buffer
@@ -21,11 +20,6 @@ public:
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 bufferInfo{};
+2 -2
View File
@@ -5,14 +5,14 @@
#include "VertexDescriptor.h"
struct Vertex {
glm::vec2 pos;
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
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, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord));
return descriptor;
+59 -259
View File
@@ -1,36 +1,38 @@
#include "FileSystem.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 "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 <vector>
#include <optional>
#include <set>
#include <glm/glm.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <glm/gtc/matrix_transform.hpp>
#include <chrono>
#include <vector>
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.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}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}
Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.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.5f}, {0.0f, 0.0f, 1.0f}, {1.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 = {
0, 1, 2, 2, 3, 0
0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4
};
struct alignas(64) ShaderUniform
@@ -46,40 +48,30 @@ class Application final
private:
std::unique_ptr<Instance> instance;
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<IndexBuffer> indexBuffer;
std::unique_ptr<UniformBuffer> shaderUniformBuffer;
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;
std::unique_ptr<CommandBuffer> commandBuffer;
public:
Application()
{
InitializeInstance();
InitializeGraphicsPipeline();
InitializeTextureImage();
InitializeTextureImageView();
InitializeTextureSampler();
InitializeUniformBuffer();
InitializeDescriptorSets();
InitializeVertexBuffer();
InitializeIndexBuffer();
InitializeCommandBuffers();
InitializeCommandBuffer();
}
~Application()
{
vkDeviceWaitIdle(instance->GetDevice());
vkDestroyImage(instance->GetDevice(), textureImage, nullptr);
vkFreeMemory(instance->GetDevice(), textureImageMemory, nullptr);
vkDestroyImageView(instance->GetDevice(), textureImageView, nullptr);
}
Application(Application&&) = delete;
@@ -92,9 +84,9 @@ public:
if (!instance->BeginPresent())
return true;
RecordCommandBuffer(commandBuffers[instance->GetFlightIndex()]);
RecordCommandBuffer();
commandBuffer->SubmitAsGraphicsQueue();
instance->SubmitGraphicsQueue(std::vector<VkCommandBuffer>{commandBuffers[instance->GetFlightIndex()]});
return instance->EndPresent();
}
@@ -105,184 +97,9 @@ private:
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()
{
sampler = std::make_unique<Sampler>(*instance, textureImageView);
}
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, &region);
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);
texture2D = std::make_unique<Texture2D>(*instance, "res/textures/texture.png");
}
void InitializeUniformBuffer()
@@ -294,18 +111,16 @@ private:
{
descriptorPool = std::make_unique<DescriptorPool>(*instance);
uniformDescriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
uniformDescriptorSet->AddUniform(*shaderUniformBuffer, 0);
samplerDescriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(1));
samplerDescriptorSet->AddSampler(*sampler, 0);
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
descriptorSet->AddTexture2D(*texture2D, 1);
}
void InitializeGraphicsPipeline()
{
PipelineCreator creator{"res/shaders/vert.spv", "res/shaders/frag.spv"};
creator.AddDescriptorSetLayoutBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
creator.AddDescriptorSetLayoutBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
PipelineCreator creator{"res/shaders/shader.vert", "res/shaders/shader.frag"};
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
creator.SetVertexDescriptor(Vertex::GetDescriptor());
creator.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
@@ -324,30 +139,17 @@ private:
indexBuffer->UpdateStaging((void*)indices.data());
}
void InitializeCommandBuffers()
void InitializeCommandBuffer()
{
commandBuffers.resize(instance->GetMaxFramesInFlight());
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");
commandBuffer = std::make_unique<CommandBuffer>(*instance, CommandBufferType::Dynamic);
}
void RecordCommandBuffer(VkCommandBuffer commandBuffer)
void RecordCommandBuffer()
{
vkResetCommandBuffer(commandBuffer, 0);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
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}}};
commandBuffer->Begin();
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
// TODO: framebuffer->Bind();
VkRenderPassBeginInfo renderPassBeginInfo{};
@@ -356,27 +158,24 @@ private:
renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer->GetHandle(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
graphicsPipeline->Bind(commandBuffer);
graphicsPipeline->Bind(commandBuffer->GetHandle());
UpdateUniformBuffer();
vertexBuffer->Bind(commandBuffer);
indexBuffer->Bind(commandBuffer);
shaderUniformBuffer->Bind(commandBuffer);
vertexBuffer->Bind(commandBuffer->GetHandle());
indexBuffer->Bind(commandBuffer->GetHandle());
std::vector<VkDescriptorSet> sets{uniformDescriptorSet->GetHandle(), samplerDescriptorSet->GetHandle()};
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
// Replace the two lines above with this somehow:
// graphicsPipeline->BindDescriptorSets(uniformDescriptorSet, samplerDescriptorSet);
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
indexBuffer->Draw(commandBuffer);
indexBuffer->Draw(commandBuffer->GetHandle());
vkCmdEndRenderPass(commandBuffer);
CP_VK_ASSERT(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer");
vkCmdEndRenderPass(commandBuffer->GetHandle());
commandBuffer->End();
}
void UpdateUniformBuffer()
@@ -386,9 +185,10 @@ private:
float time = startTimer.Elapsed();
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.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.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);
}
@@ -419,7 +219,7 @@ int main()
glfwPollEvents();
if (timer.Elapsed() >= 1.0)
{
std::cout << frames << "fps" << std::endl;
CP_DEBUG("%d fps", frames);
frames = 0;
timer.Start();
}