Refactoring Samplers

- Add Sampler base class
- Add ColorAttachment, DepthAttachment classes
- Add function name to all traces
- Add Framebuffer resizing
This commit is contained in:
Thraix
2023-02-05 22:13:21 +01:00
parent 88979a5ab9
commit c2e349eb56
26 changed files with 625 additions and 540 deletions
+4
View File
@@ -168,6 +168,9 @@
<ClCompile Include="src\Texture2D.cpp" /> <ClCompile Include="src\Texture2D.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\DepthAttachment.h" />
<ClInclude Include="src\Application.h" />
<ClInclude Include="src\ColorAttachment.h" />
<ClInclude Include="src\Buffer.h" /> <ClInclude Include="src\Buffer.h" />
<ClInclude Include="src\CommandBuffer.h" /> <ClInclude Include="src\CommandBuffer.h" />
<ClInclude Include="src\Common.h" /> <ClInclude Include="src\Common.h" />
@@ -180,6 +183,7 @@
<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\Shader.h" />
<ClInclude Include="src\Texture2D.h" /> <ClInclude Include="src\Texture2D.h" />
<ClInclude Include="src\CommandBufferScoped.h" /> <ClInclude Include="src\CommandBufferScoped.h" />
+3
View File
@@ -24,6 +24,9 @@
<ClCompile Include="src\Texture2D.cpp"> <ClCompile Include="src\Texture2D.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Application.h">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\DebugMessenger.h"> <ClInclude Include="src\DebugMessenger.h">
+1 -1
View File
@@ -6,6 +6,6 @@ layout(location = 0) out vec2 fragTexCoord;
void main() void main()
{ {
gl_Position = vec4(inPosition* 0.5, 0.999, 1.0); gl_Position = vec4(inPosition * 0.5, 0.999, 1.0);
fragTexCoord = inPosition * 0.5 + 0.5; fragTexCoord = inPosition * 0.5 + 0.5;
} }
+10 -8
View File
@@ -103,8 +103,15 @@ namespace Copium
bool Update() bool Update()
{ {
if (framebuffer->GetWidth() != instance->GetSwapChain().GetExtent().width || framebuffer->GetHeight() != instance->GetSwapChain().GetExtent().height)
{
framebuffer->Resize(instance->GetSwapChain().GetExtent().width / 8, instance->GetSwapChain().GetExtent().height / 8);
descriptorSetPassthrough->AddSampler(framebuffer->GetColorAttachment(), 0);
}
if (!instance->BeginPresent()) if (!instance->BeginPresent())
{
return true; return true;
}
RecordCommandBuffer(); RecordCommandBuffer();
commandBuffer->SubmitAsGraphicsQueue(); commandBuffer->SubmitAsGraphicsQueue();
@@ -140,10 +147,10 @@ namespace Copium
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0)); descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
descriptorSet->AddUniform(*shaderUniformBuffer, 0); descriptorSet->AddUniform(*shaderUniformBuffer, 0);
descriptorSet->AddTexture2D(*texture2D, 1); descriptorSet->AddSampler(*texture2D, 1);
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0)); descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0); descriptorSetPassthrough->AddSampler(framebuffer->GetColorAttachment(), 0);
} }
void InitializeGraphicsPipeline() void InitializeGraphicsPipeline()
@@ -188,11 +195,6 @@ namespace Copium
void RecordCommandBuffer() void RecordCommandBuffer()
{ {
commandBuffer->Begin(); commandBuffer->Begin();
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
framebuffer->Bind(*commandBuffer); framebuffer->Bind(*commandBuffer);
graphicsPipeline->Bind(*commandBuffer); graphicsPipeline->Bind(*commandBuffer);
@@ -228,7 +230,7 @@ namespace Copium
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), framebuffer->GetWidth() / (float)framebuffer->GetHeight(), 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}; 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};
+7 -7
View File
@@ -30,7 +30,7 @@ namespace Copium
createInfo.usage = usage; createInfo.usage = usage;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
CP_VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer"); CP_VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Buffer : Failed to initialize buffer");
VkMemoryRequirements memoryRequirements; VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements); vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements);
@@ -40,7 +40,7 @@ namespace Copium
allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties); allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Failed to allocate buffer memory"); CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Buffer : Failed to allocate buffer memory");
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0); vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
} }
@@ -53,7 +53,7 @@ namespace Copium
void Update(void* indexData, int index) void Update(void* indexData, int index)
{ {
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer"); CP_ASSERT(index >= 0 && index < count, "Update : Index is outside of the buffer");
if (mappedData == nullptr) if (mappedData == nullptr)
{ {
@@ -89,14 +89,14 @@ namespace Copium
void* Map() void* Map()
{ {
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer"); CP_ASSERT(mappedData == nullptr, "Map : Mapping an already mapped buffer");
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData); vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
return mappedData; return mappedData;
} }
void Unmap() void Unmap()
{ {
CP_ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer"); CP_ASSERT(mappedData != nullptr, "Unmap : Unmapping an already unmapped buffer");
vkUnmapMemory(instance.GetDevice(), memory); vkUnmapMemory(instance.GetDevice(), memory);
mappedData = nullptr; mappedData = nullptr;
@@ -128,7 +128,7 @@ namespace Copium
VkDeviceSize GetPosition(int index) const VkDeviceSize GetPosition(int index) const
{ {
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer"); CP_ASSERT(index >= 0 && index < count, "GetPosition : Index is outside of the buffer");
return size * (VkDeviceSize)index; return size * (VkDeviceSize)index;
} }
@@ -142,7 +142,7 @@ namespace Copium
allocateInfo.commandBufferCount = 1; allocateInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer; VkCommandBuffer commandBuffer;
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer"); CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "CopyBuffer : Failed to initialize command buffer");
VkCommandBufferBeginInfo beginInfo{}; VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include "Common.h"
#include "Instance.h"
#include "Image.h"
#include "Sampler.h"
namespace Copium
{
class ColorAttachment : public Sampler
{
CP_DELETE_COPY_AND_MOVE_CTOR(ColorAttachment);
private:
std::vector<VkImage> images;
std::vector<VkDeviceMemory> imageMemories;
std::vector<VkImageView> imageViews;
public:
ColorAttachment(Instance& instance, int width, int height)
: Sampler{instance}
{
InitializeColorAttachment(width, height);
}
~ColorAttachment() override
{
for (auto&& image : images)
vkDestroyImage(instance.GetDevice(), image, nullptr);
for (auto&& imageMemory : imageMemories)
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
for (auto&& imageView : imageViews)
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
}
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override
{
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for color attachment");
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler;
imageInfo.imageView = imageViews[index];
return imageInfo;
}
VkImageView GetImageView(int index)
{
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetImageView : Index out of bound");
return imageViews[index];
}
private:
void InitializeColorAttachment(int width, int height)
{
images.resize(instance.GetMaxFramesInFlight());
imageMemories.resize(instance.GetMaxFramesInFlight());
imageViews.resize(instance.GetMaxFramesInFlight());
for (size_t i = 0; i < images.size(); i++)
{
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
};
}
+3 -3
View File
@@ -35,7 +35,7 @@ namespace Copium
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandPool = instance.GetCommandPool(); allocateInfo.commandPool = instance.GetCommandPool();
allocateInfo.commandBufferCount = commandBuffers.size(); allocateInfo.commandBufferCount = commandBuffers.size();
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, commandBuffers.data()), "Failed to allocate CommandBuffer"); CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, commandBuffers.data()), "CommandBuffer : Failed to allocate CommandBuffer");
} }
~CommandBuffer() ~CommandBuffer()
@@ -65,11 +65,11 @@ namespace Copium
currentCommandBuffer = commandBuffers[instance.GetFlightIndex()]; currentCommandBuffer = commandBuffers[instance.GetFlightIndex()];
break; break;
default: default:
CP_WARN("Unhandled enum case: %d", (int)type); CP_ABORT("Begin : Unreachable switch case");
} }
vkResetCommandBuffer(currentCommandBuffer, 0); vkResetCommandBuffer(currentCommandBuffer, 0);
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Failed to begin command buffer"); CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Begin : Failed to begin command buffer");
} }
void End() void End()
+1 -1
View File
@@ -57,7 +57,7 @@ namespace Copium
std::string StringFormat(const std::string& format, Args... args) std::string StringFormat(const std::string& format, Args... args)
{ {
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
CP_ASSERT(size > 0, "Error during formatting"); CP_ASSERT(size > 0, "StringFormat : Error during formatting");
std::unique_ptr<char[]> buf(new char[size]); std::unique_ptr<char[]> buf(new char[size]);
std::snprintf(buf.get(), size, format.c_str(), args...); std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); return std::string(buf.get(), buf.get() + size - 1);
+4 -6
View File
@@ -25,7 +25,7 @@ namespace Copium
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = DebugCallback; createInfo.pfnUserCallback = DebugCallback;
createInfo.pUserData = nullptr; createInfo.pUserData = nullptr;
CP_VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "Failed to initialze debug messenger"); CP_VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "DebugMessenger : Failed to initialze debug messenger");
#endif #endif
} }
@@ -59,11 +59,9 @@ namespace Copium
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{ {
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{ CP_ABORT("DebugCallback : %s", pCallbackData->pMessage);
CP_ERR(pCallbackData->pMessage); else
throw VulkanException(pCallbackData->pMessage); CP_WARN("DebugCallback : %s", pCallbackData->pMessage);
}
CP_WARN(pCallbackData->pMessage);
} }
return VK_FALSE; return VK_FALSE;
} }
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include "Common.h"
#include "Instance.h"
#include "Image.h"
#include "Sampler.h"
namespace Copium
{
class DepthAttachment : public Sampler
{
CP_DELETE_COPY_AND_MOVE_CTOR(DepthAttachment);
private:
VkImage image;
VkDeviceMemory imageMemory;
VkImageView imageView;
public:
DepthAttachment(Instance& instance, int width, int height)
: Sampler{instance}
{
InitializeDepthAttachment(width, height);
}
~DepthAttachment() override
{
vkDestroyImage(instance.GetDevice(), image, nullptr);
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
}
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override
{
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler;
imageInfo.imageView = imageView;
return imageInfo;
}
VkImageView GetImageView() const
{
return imageView;
}
private:
void InitializeDepthAttachment(int width, int height)
{
VkFormat depthFormat = Image::SelectDepthFormat(instance);
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
imageView = Image::InitializeImageView(instance, image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
}
};
}
+2 -2
View File
@@ -32,7 +32,7 @@ namespace Copium
createInfo.maxSets = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); createInfo.maxSets = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight();
createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; 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), "DescriptorPool : Failed to initialize descriptor pool");
} }
~DescriptorPool() ~DescriptorPool()
@@ -51,7 +51,7 @@ namespace Copium
allocateInfo.pSetLayouts = layouts.data(); allocateInfo.pSetLayouts = layouts.data();
descriptorSets.resize(instance.GetMaxFramesInFlight()); descriptorSets.resize(instance.GetMaxFramesInFlight());
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets"); CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "AllocateDescriptorSets : Failed to allocate descriptor sets");
return descriptorSets; return descriptorSets;
} }
+4 -3
View File
@@ -2,8 +2,9 @@
#include "Common.h" #include "Common.h"
#include "DescriptorPool.h" #include "DescriptorPool.h"
#include "Texture2D.h" #include "Sampler.h"
#include "UniformBuffer.h" #include "UniformBuffer.h"
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Copium namespace Copium
@@ -49,10 +50,10 @@ namespace Copium
} }
} }
void AddTexture2D(const Texture2D& texture2D, uint32_t binding) void AddSampler(const Sampler& sampler, uint32_t binding)
{ {
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) { for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i); VkDescriptorImageInfo imageInfo = sampler.GetDescriptorImageInfo(i);
VkWriteDescriptorSet descriptorWrite{}; VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i]; descriptorWrite.dstSet = descriptorSets[i];
+10 -8
View File
@@ -1,12 +1,12 @@
#pragma once #pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include <filesystem>
#include "Common.h" #include "Common.h"
#include <filesystem>
#include <fstream> #include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
namespace Copium namespace Copium
{ {
@@ -17,7 +17,7 @@ namespace Copium
static std::vector<char> ReadFile(const std::string& filename) static std::vector<char> ReadFile(const std::string& filename)
{ {
std::ifstream file(filename, std::ios::ate | std::ios::binary); std::ifstream file(filename, std::ios::ate | std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file"); CP_ASSERT(file.is_open(), "ReadFile : Failed to open file");
size_t fileSize = (size_t)file.tellg(); size_t fileSize = (size_t)file.tellg();
std::vector<char> buffer(fileSize); std::vector<char> buffer(fileSize);
@@ -31,7 +31,7 @@ namespace Copium
static std::string ReadFileStr(const std::string& filename) static std::string ReadFileStr(const std::string& filename)
{ {
std::ifstream file(filename, std::ios::ate | std::ios::binary); std::ifstream file(filename, std::ios::ate | std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file"); CP_ASSERT(file.is_open(), "ReadFileStr : Failed to open file");
size_t fileSize = (size_t)file.tellg(); size_t fileSize = (size_t)file.tellg();
std::string buffer; std::string buffer;
@@ -45,8 +45,10 @@ namespace Copium
static void WriteFile(const std::string& filename, const std::string& data) static void WriteFile(const std::string& filename, const std::string& data)
{ {
std::filesystem::path path{filename};
std::filesystem::create_directories(path.parent_path());
std::ofstream file(filename, std::ios::binary); std::ofstream file(filename, std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file"); CP_ASSERT(file.is_open(), "WriteFile : Failed to open file");
file.write(data.c_str(), data.size()); file.write(data.c_str(), data.size());
} }
@@ -56,7 +58,7 @@ namespace Copium
std::filesystem::path path{filename}; std::filesystem::path path{filename};
std::filesystem::create_directories(path.parent_path()); std::filesystem::create_directories(path.parent_path());
std::ofstream file(filename, std::ios::binary); std::ofstream file(filename, std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file"); CP_ASSERT(file.is_open(), "WriteFile : Failed to open file");
file.write(data, size); file.write(data, size);
} }
@@ -70,7 +72,7 @@ namespace Copium
static int64_t DateModified(const std::string& filename) static int64_t DateModified(const std::string& filename)
{ {
struct stat result; struct stat result;
CP_ASSERT(stat(filename.c_str(), &result) == 0, "Cannot stat file %s", filename.c_str()); CP_ASSERT(stat(filename.c_str(), &result) == 0, "DataModified : Cannot stat file %s", filename.c_str());
return (int64_t)result.st_mtime; return (int64_t)result.st_mtime;
} }
}; };
+49 -12
View File
@@ -3,21 +3,21 @@
#include "Common.h" #include "Common.h"
#include "Image.h" #include "Image.h"
#include "Instance.h" #include "Instance.h"
#include "Texture2D.h" #include "ColorAttachment.h"
#include "DepthAttachment.h"
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Copium namespace Copium
{ {
// TODO: Add resizing (recreate image, depthImage, framebuffers)
class Framebuffer class Framebuffer
{ {
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer); CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
private: private:
Instance& instance; Instance& instance;
std::unique_ptr<Texture2D> image; std::unique_ptr<ColorAttachment> colorAttachment;
std::unique_ptr<Texture2D> depthImage; std::unique_ptr<DepthAttachment> depthAttachment;
std::vector<VkFramebuffer> framebuffers; std::vector<VkFramebuffer> framebuffers;
VkRenderPass renderPass; VkRenderPass renderPass;
@@ -27,7 +27,7 @@ namespace Copium
Framebuffer(Instance& instance, uint32_t width, uint32_t height) Framebuffer(Instance& instance, uint32_t width, uint32_t height)
: instance{instance}, width{width}, height{height} : instance{instance}, width{width}, height{height}
{ {
InitializeImages(); InitializeImage();
InitializeDepthBuffer(); InitializeDepthBuffer();
InitializeRenderPass(); InitializeRenderPass();
InitializeFramebuffers(); InitializeFramebuffers();
@@ -40,6 +40,20 @@ namespace Copium
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr); vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
} }
void Resize(uint32_t width, uint32_t height)
{
vkDeviceWaitIdle(instance.GetDevice());
this->width = width;
this->height = height;
colorAttachment.reset();
depthAttachment.reset();
for (auto&& framebuffer : framebuffers)
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
InitializeImage();
InitializeDepthBuffer();
InitializeFramebuffers();
}
void Bind(const CommandBuffer& commandBuffer) void Bind(const CommandBuffer& commandBuffer)
{ {
std::vector<VkClearValue> clearValues{2}; std::vector<VkClearValue> clearValues{2};
@@ -55,6 +69,19 @@ namespace Copium
renderPassBeginInfo.clearValueCount = clearValues.size(); renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data(); renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = width;
viewport.height = height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = {width, height};
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
} }
void Unbind(const CommandBuffer& commandBuffer) void Unbind(const CommandBuffer& commandBuffer)
@@ -72,21 +99,31 @@ namespace Copium
return framebuffers[instance.GetFlightIndex()]; return framebuffers[instance.GetFlightIndex()];
} }
const Texture2D& GetTexture2D() const const ColorAttachment& GetColorAttachment() const
{ {
return *image; return *colorAttachment;
}
uint32_t GetWidth() const
{
return width;
}
uint32_t GetHeight() const
{
return height;
} }
private: private:
void InitializeImages() void InitializeImage()
{ {
image = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color); colorAttachment = std::make_unique<ColorAttachment>(instance, width, height);
} }
void InitializeDepthBuffer() void InitializeDepthBuffer()
{ {
depthImage = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Static, Texture2D::Format::Depth); depthAttachment = std::make_unique<DepthAttachment>(instance, width, height);
} }
void InitializeRenderPass() void InitializeRenderPass()
@@ -159,7 +196,7 @@ namespace Copium
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
{ {
std::vector<VkImageView> attachments{image->GetImageView(i), depthImage->GetImageView()}; std::vector<VkImageView> attachments{colorAttachment->GetImageView(i), depthAttachment->GetImageView()};
VkFramebufferCreateInfo createInfo{}; VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
@@ -170,7 +207,7 @@ namespace Copium
createInfo.height = height; createInfo.height = height;
createInfo.layers = 1; createInfo.layers = 1;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer"); CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize framebuffer");
} }
} }
}; };
+18 -18
View File
@@ -53,7 +53,7 @@ namespace Copium
InitializeCommandPool(); InitializeCommandPool();
InitializeSwapChain(); InitializeSwapChain();
InitializeSyncObjects(); InitializeSyncObjects();
CP_INFO("Initialized Vulkan in %f seconds", timer.Elapsed()); CP_INFO("Instance : Initialized Vulkan in %f seconds", timer.Elapsed());
} }
~Instance() ~Instance()
@@ -106,7 +106,7 @@ namespace Copium
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderFinishedSemaphores[flightIndex]; submitInfo.pSignalSemaphores = &renderFinishedSemaphores[flightIndex];
CP_VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[flightIndex]), "Failed to submit command buffer"); CP_VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[flightIndex]), "SubmitGraphicsQueue : Failed to submit command buffer");
} }
VkInstance GetInstance() const VkInstance GetInstance() const
@@ -169,7 +169,7 @@ namespace Copium
if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
return i; return i;
} }
throw std::runtime_error("Failed to find suitable memory type"); CP_ABORT("FindMemoryType : Failed to find suitable memory type");
} }
private: private:
@@ -190,7 +190,7 @@ namespace Copium
#else #else
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr); window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
#endif #endif
CP_ASSERT(window, "Failed to initialize glfw window"); CP_ASSERT(window, "InitializeWindow : Failed to initialize glfw window");
glfwSetWindowUserPointer(window, this); glfwSetWindowUserPointer(window, this);
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback); glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
@@ -213,7 +213,7 @@ namespace Copium
std::vector<VkExtensionProperties> extensions{extensionCount}; std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
CP_INFO("Supported Extensions:"); CP_INFO("InitiaizeInstace : Supported Extensions:");
for (auto&& extension : extensions) for (auto&& extension : extensions)
{ {
CP_INFO_CONT("\t%s", extension.extensionName); CP_INFO_CONT("\t%s", extension.extensionName);
@@ -221,7 +221,7 @@ namespace Copium
std::vector<const char*> layers{}; std::vector<const char*> layers{};
DebugMessenger::AddRequiredLayers(&layers); DebugMessenger::AddRequiredLayers(&layers);
CP_ASSERT(CheckLayerSupport(layers), "Some required layers are not supported"); CP_ASSERT(CheckLayerSupport(layers), "InitializeInstance : Some required layers are not supported");
VkInstanceCreateInfo createInfo{}; VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
@@ -230,7 +230,7 @@ namespace Copium
createInfo.ppEnabledExtensionNames = requiredExtensions.data(); createInfo.ppEnabledExtensionNames = requiredExtensions.data();
createInfo.enabledLayerCount = layers.size(); createInfo.enabledLayerCount = layers.size();
createInfo.ppEnabledLayerNames = layers.data(); createInfo.ppEnabledLayerNames = layers.data();
CP_VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance"); CP_VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "InitializeInstance : Failed to create instance");
} }
void InitializeDebugMessenger() void InitializeDebugMessenger()
@@ -240,18 +240,18 @@ namespace Copium
void InitializeSurface() void InitializeSurface()
{ {
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface"); CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "InitializeSurface : Failed to create Vulkan surface");
} }
void SelectPhysicalDevice() void SelectPhysicalDevice()
{ {
uint32_t deviceCount; uint32_t deviceCount;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
CP_ASSERT(deviceCount != 0, "No available devices support Vulkan"); CP_ASSERT(deviceCount != 0, "SelectPhysicaDevice : No available devices support Vulkan");
std::vector<VkPhysicalDevice> devices(deviceCount); std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
CP_INFO("Available devices:"); CP_INFO("SelectPhysicaDevice : Available devices:");
for (auto&& device : devices) for (auto&& device : devices)
{ {
VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceProperties deviceProperties;
@@ -265,11 +265,11 @@ namespace Copium
VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties); vkGetPhysicalDeviceProperties(device, &deviceProperties);
physicalDevice = device; physicalDevice = device;
CP_INFO("Selecting device: %s", deviceProperties.deviceName); CP_INFO("SelectPhysicaDevice : Selecting device: %s", deviceProperties.deviceName);
break; break;
} }
} }
CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU"); CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "SelectPhysicaDevice : Failed to find suitable GPU");
} }
void InitializeLogicalDevice() void InitializeLogicalDevice()
@@ -301,7 +301,7 @@ namespace Copium
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledExtensionCount = deviceExtensions.size(); createInfo.enabledExtensionCount = deviceExtensions.size();
CP_VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device"); CP_VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "InitializeLogicalDevice : Failed to initialize logical device");
graphicsQueueIndex = query.graphicsFamily.value(); graphicsQueueIndex = query.graphicsFamily.value();
presentQueueIndex = query.presentFamily.value(); presentQueueIndex = query.presentFamily.value();
@@ -320,7 +320,7 @@ namespace Copium
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
createInfo.queueFamilyIndex = graphicsQueueIndex; createInfo.queueFamilyIndex = graphicsQueueIndex;
CP_VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool"); CP_VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "InitializeCommandPool : Failed to initialize command pool");
} }
void InitializeSyncObjects() void InitializeSyncObjects()
@@ -332,14 +332,14 @@ namespace Copium
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
{ {
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore"); CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "InitializeSyncObjects : Failed to initialize available image semaphore");
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore"); CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "InitializeSyncObjects : Failed to initialize render finished semaphore");
VkFenceCreateInfo fenceCreateInfo{}; VkFenceCreateInfo fenceCreateInfo{};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
CP_VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence"); CP_VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "InitializeSyncObjects : Failed to initialize in flight fence");
} }
} }
@@ -364,7 +364,7 @@ namespace Copium
std::vector<VkLayerProperties> availableLayers(layerCount); std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
CP_INFO("Supported Layers:"); CP_INFO("CheckLayerSupport : Supported Layers:");
for (auto&& availableLayer : availableLayers) for (auto&& availableLayer : availableLayers)
{ {
CP_INFO_CONT("\t%s", availableLayer.layerName); CP_INFO_CONT("\t%s", availableLayer.layerName);
+7 -34
View File
@@ -45,24 +45,11 @@ namespace Copium
void Bind(const CommandBuffer& commandBuffer) void Bind(const CommandBuffer& commandBuffer)
{ {
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = instance.GetSwapChain().GetExtent().width;
viewport.height = instance.GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = instance.GetSwapChain().GetExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
} }
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet) void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
{ {
CP_ASSERT(setIndex < boundDescriptorSets.size(), "DescriptorSet index is out of bounds"); CP_ASSERT(setIndex < boundDescriptorSets.size(), "SetDescriptorSet : DescriptorSet index is out of bounds");
boundDescriptorSets[setIndex] = descriptorSet.GetHandle(); boundDescriptorSets[setIndex] = descriptorSet.GetHandle();
} }
@@ -101,7 +88,7 @@ namespace Copium
createInfo.bindingCount = layoutBindings.size(); createInfo.bindingCount = layoutBindings.size();
createInfo.pBindings = layoutBindings.data(); 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++]), "InitializeDescriptorSetLayout : Failed to initialize descriptor set layout");
} }
} }
@@ -124,14 +111,14 @@ namespace Copium
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0; viewport.x = 0;
viewport.y = 0; viewport.y = 0;
viewport.width = instance.GetSwapChain().GetExtent().width; viewport.width = 1;
viewport.height = instance.GetSwapChain().GetExtent().height; viewport.height = 1;
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
VkRect2D scissor{}; VkRect2D scissor{};
scissor.offset = {0, 0}; scissor.offset = {0, 0};
scissor.extent = instance.GetSwapChain().GetExtent(); scissor.extent = {1, 1};
std::vector<VkDynamicState> dynamicStates = { std::vector<VkDynamicState> dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_VIEWPORT,
@@ -217,7 +204,7 @@ namespace Copium
pipelineLayoutCreateInfo.pushConstantRangeCount = 0; pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr; pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "Failed to initialize pipeline layout"); CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "InitializePipeline : Failed to initialize pipeline layout");
const std::vector<VkPipelineShaderStageCreateInfo>& shaderStages = shader.GetShaderStages(); const std::vector<VkPipelineShaderStageCreateInfo>& shaderStages = shader.GetShaderStages();
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{}; VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
@@ -238,21 +225,7 @@ namespace Copium
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
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), "InitializePipeline : Failed to initialize graphics pipeline");
} }
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
{
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule;
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
return shaderModule;
}
}; };
} }
-1
View File
@@ -33,7 +33,6 @@ namespace Copium
} }
i++; i++;
} }
} }
bool AllRequiredFamiliesSupported() bool AllRequiredFamiliesSupported()
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "Common.h"
#include "Instance.h"
#include <vulkan/vulkan.hpp>
namespace Copium
{
class Sampler
{
CP_DELETE_COPY_AND_MOVE_CTOR(Sampler);
protected:
Instance& instance;
VkSampler sampler;
public:
Sampler(Instance& instance)
: instance{instance}
{
InitializeSampler();
}
virtual ~Sampler()
{
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
}
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), "InitializeSampler : Failed to initialize texture sampler");
}
virtual VkDescriptorImageInfo GetDescriptorImageInfo(int index) const = 0;
};
}
+7 -7
View File
@@ -46,7 +46,7 @@ namespace Copium
fragShaderModule = InitializeShaderModule(FileSystem::ReadFile(fragmentInput)); fragShaderModule = InitializeShaderModule(FileSystem::ReadFile(fragmentInput));
break; break;
default: default:
CP_ASSERT(false, "Unreachable switch case %d", (int)type); CP_ASSERT(false, "Shader : Unreachable switch case %d", (int)type);
} }
shaderStages.resize(2); shaderStages.resize(2);
@@ -99,7 +99,7 @@ namespace Copium
{ {
if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename)) if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename))
{ {
CP_DEBUG("Loading cached shader file: %s", filename.c_str()); CP_DEBUG("InitializeShaderModuleFromGlslFile : Loading cached shader file: %s", filename.c_str());
std::vector<char> data = FileSystem::ReadFile(spvFilename); std::vector<char> data = FileSystem::ReadFile(spvFilename);
CP_ASSERT(data.size() % 4 == 0, "Spv data size is not a factor of 4"); CP_ASSERT(data.size() % 4 == 0, "Spv data size is not a factor of 4");
return InitializeShaderModule((const uint32_t*)data.data(), data.size()); return InitializeShaderModule((const uint32_t*)data.data(), data.size());
@@ -108,9 +108,9 @@ namespace Copium
} }
catch (const std::runtime_error& e) catch (const std::runtime_error& e)
{ {
CP_WARN("Cached shader file is invalid, recreating it"); CP_WARN("InitializeShaderModuleFromGlslFile : Cached shader file is invalid, recreating it");
} }
CP_DEBUG("Compiling shader file: %s", filename.c_str()); CP_DEBUG("InitializeShaderModuleFromGlslFile : Compiling shader file: %s", filename.c_str());
shaderc::Compiler compiler; shaderc::Compiler compiler;
shaderc::CompileOptions options; shaderc::CompileOptions options;
@@ -118,7 +118,7 @@ namespace Copium
std::vector<char> glslCode = FileSystem::ReadFile(filename); std::vector<char> glslCode = FileSystem::ReadFile(filename);
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(glslCode.data(), glslCode.size(), type, filename.c_str(), options); shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(glslCode.data(), glslCode.size(), type, 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()); CP_ASSERT(result.GetCompilationStatus() == shaderc_compilation_status_success, "InitializeShaderModuleFromGlslFile : Failed to compile shader: %s\n%s", filename.c_str(), result.GetErrorMessage().c_str());
std::vector<uint32_t> data{result.cbegin(), result.cend()}; std::vector<uint32_t> data{result.cbegin(), result.cend()};
FileSystem::WriteFile(spvFilename, (const char*)data.data(), data.size() * sizeof(uint32_t)); FileSystem::WriteFile(spvFilename, (const char*)data.data(), data.size() * sizeof(uint32_t));
@@ -133,7 +133,7 @@ namespace Copium
options.SetOptimizationLevel(shaderc_optimization_level_size); options.SetOptimizationLevel(shaderc_optimization_level_size);
shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(code.data(), type, "inline_shader_code", options); shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(code.data(), type, "inline_shader_code", options);
CP_ASSERT(result.GetCompilationStatus() == shaderc_compilation_status_success, "Failed to compile inline shader code: %s", result.GetErrorMessage()); CP_ASSERT(result.GetCompilationStatus() == shaderc_compilation_status_success, "InitializeShaderModuleFromGlslCode : Failed to compile inline shader code: %s", result.GetErrorMessage());
std::vector<uint32_t> data{result.cbegin(), result.cend()}; std::vector<uint32_t> data{result.cbegin(), result.cend()};
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t)); return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
@@ -147,7 +147,7 @@ namespace Copium
createInfo.pCode = data; createInfo.pCode = data;
VkShaderModule shaderModule; VkShaderModule shaderModule;
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module"); CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "InitializeShaderModule : Failed to initialize shader module");
return shaderModule; return shaderModule;
} }
+299 -286
View File
@@ -1,345 +1,358 @@
#include "SwapChain.h" #include "SwapChain.h"
#include "CommandBuffer.h" #include "CommandBuffer.h"
#include "DepthAttachment.h"
#include "Image.h" #include "Image.h"
#include "Instance.h" #include "Instance.h"
#include "QueueFamilies.h" #include "QueueFamilies.h"
#include "Texture2D.h"
#include <glfw/glfw3.h> #include <glfw/glfw3.h>
#include <vulkan/vulkan.h>
#include <vector> #include <vector>
#include <vulkan/vulkan.h>
namespace Copium namespace Copium
{ {
SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice) SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice)
{ {
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);
uint32_t formatCount; uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr); vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
if (formatCount != 0) if (formatCount != 0)
{ {
formats.resize(formatCount); formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data()); vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
} }
uint32_t presentModeCount; uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
if (presentModeCount != 0) if (presentModeCount != 0)
{ {
presentModes.resize(presentModeCount); presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()); vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
} }
} }
bool SwapChainSupportDetails::Valid() bool SwapChainSupportDetails::Valid()
{ {
return !formats.empty() && !presentModes.empty(); return !formats.empty() && !presentModes.empty();
} }
SwapChain::SwapChain(Instance& instance) SwapChain::SwapChain(Instance& instance)
: instance{instance} : instance{instance}
{ {
Initialize(); Initialize();
InitializeImageViews(); InitializeImageViews();
InitializeDepthBuffer(); InitializeDepthAttachment();
InitializeRenderPass(); InitializeRenderPass();
InitializeFramebuffers(); InitializeFramebuffers();
} }
SwapChain::~SwapChain() SwapChain::~SwapChain()
{ {
Destroy(); Destroy();
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr); vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
} }
void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const
{ {
std::vector<VkClearValue> clearValues{2}; std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}}; clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0}; clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{}; VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[imageIndex]; renderPassBeginInfo.framebuffer = framebuffers[imageIndex];
renderPassBeginInfo.renderArea.offset = {0, 0}; renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = extent; renderPassBeginInfo.renderArea.extent = extent;
renderPassBeginInfo.clearValueCount = clearValues.size(); renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data(); renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const VkViewport viewport{};
{ viewport.x = 0.0f;
vkCmdEndRenderPass(commandBuffer); viewport.y = 0.0f;
} viewport.width = extent.width;
viewport.height = extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = extent;
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
}
VkSwapchainKHR SwapChain::GetHandle() const void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const
{ {
return handle; vkCmdEndRenderPass(commandBuffer);
} }
VkRenderPass SwapChain::GetRenderPass() const VkSwapchainKHR SwapChain::GetHandle() const
{ {
return renderPass; return handle;
} }
VkExtent2D SwapChain::GetExtent() const VkRenderPass SwapChain::GetRenderPass() const
{ {
return extent; return renderPass;
} }
VkFramebuffer SwapChain::GetFramebuffer() const VkExtent2D SwapChain::GetExtent() const
{ {
return framebuffers[imageIndex]; return extent;
} }
bool SwapChain::BeginPresent(VkSemaphore signalSemaphore) VkFramebuffer SwapChain::GetFramebuffer() const
{ {
VkResult result = vkAcquireNextImageKHR(instance.GetDevice(), handle, UINT64_MAX, signalSemaphore, VK_NULL_HANDLE, &imageIndex); return framebuffers[imageIndex];
if (result == VK_ERROR_OUT_OF_DATE_KHR) }
{
Recreate();
return false;
}
return true;
}
void SwapChain::EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized) bool SwapChain::BeginPresent(VkSemaphore signalSemaphore)
{ {
VkPresentInfoKHR presentInfo{}; VkResult result = vkAcquireNextImageKHR(instance.GetDevice(), handle, UINT64_MAX, signalSemaphore, VK_NULL_HANDLE, &imageIndex);
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; if (result == VK_ERROR_OUT_OF_DATE_KHR)
presentInfo.waitSemaphoreCount = 1; {
presentInfo.pWaitSemaphores = waitSemaphore; Recreate();
presentInfo.swapchainCount = 1; return false;
presentInfo.pSwapchains = &handle; }
presentInfo.pImageIndices = &imageIndex; return true;
presentInfo.pResults = nullptr; }
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo); void SwapChain::EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized)
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
{ VkPresentInfoKHR presentInfo{};
Recreate(); presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
} presentInfo.waitSemaphoreCount = 1;
} presentInfo.pWaitSemaphores = waitSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &handle;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr;
void SwapChain::Recreate() VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
{ if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
int width = 0; {
int height = 0; Recreate();
glfwGetFramebufferSize(instance.GetWindow(), &width, &height); }
while (width == 0 || height == 0) }
{
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
glfwWaitEvents();
}
vkDeviceWaitIdle(instance.GetDevice()); void SwapChain::Recreate()
{
int width = 0;
int height = 0;
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
while (width == 0 || height == 0)
{
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
glfwWaitEvents();
}
Destroy(); vkDeviceWaitIdle(instance.GetDevice());
Initialize(); Destroy();
InitializeImageViews();
InitializeDepthBuffer();
InitializeFramebuffers();
}
void SwapChain::Initialize() Initialize();
{ InitializeImageViews();
SwapChainSupportDetails swapChainSupport{instance.GetSurface(), instance.GetPhysicalDevice()}; InitializeDepthAttachment();
InitializeFramebuffers();
}
VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats); void SwapChain::Initialize()
VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes); {
extent = SelectSwapExtent(instance.GetWindow(), swapChainSupport.capabilities); SwapChainSupportDetails swapChainSupport{instance.GetSurface(), instance.GetPhysicalDevice()};
imageFormat = format.format;
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
if (swapChainSupport.capabilities.maxImageCount != 0)
{
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
}
QueueFamiliesQuery queueFamilies{instance.GetSurface(), instance.GetPhysicalDevice()}; VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()}; VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
extent = SelectSwapExtent(instance.GetWindow(), swapChainSupport.capabilities);
imageFormat = format.format;
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
if (swapChainSupport.capabilities.maxImageCount != 0)
{
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
}
VkSwapchainCreateInfoKHR createInfo{}; QueueFamiliesQuery queueFamilies{instance.GetSurface(), instance.GetPhysicalDevice()};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
createInfo.surface = instance.GetSurface();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = format.format;
createInfo.imageColorSpace = format.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
CP_VK_ASSERT(vkCreateSwapchainKHR(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize the swapchain"); VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = instance.GetSurface();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = format.format;
createInfo.imageColorSpace = format.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, nullptr); CP_VK_ASSERT(vkCreateSwapchainKHR(instance.GetDevice(), &createInfo, nullptr, &handle), "Initialize : Failed to initialize the swapchain");
images.resize(imageCount);
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, images.data());
}
void SwapChain::InitializeImageViews() vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, nullptr);
{ images.resize(imageCount);
imageViews.resize(images.size()); vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, images.data());
for (size_t i = 0; i < images.size(); i++) }
{
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
void SwapChain::InitializeDepthBuffer() void SwapChain::InitializeImageViews()
{ {
depthImage = std::make_unique<Texture2D>(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth); imageViews.resize(images.size());
} for (size_t i = 0; i < images.size(); i++)
{
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
void SwapChain::InitializeRenderPass() void SwapChain::InitializeDepthAttachment()
{ {
VkAttachmentDescription colorAttachment{}; depthAttachment = std::make_unique<DepthAttachment>(instance, extent.width, extent.height);
colorAttachment.format = imageFormat; }
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentDescription depthAttachment{}; void SwapChain::InitializeRenderPass()
depthAttachment.format = Image::SelectDepthFormat(instance); {
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; VkAttachmentDescription colorAttachment{};
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.format = imageFormat;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef{}; VkAttachmentDescription depthAttachment{};
colorAttachmentRef.attachment = 0; depthAttachment.format = Image::SelectDepthFormat(instance);
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 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 depthAttachmentRef{}; VkAttachmentReference colorAttachmentRef{};
depthAttachmentRef.attachment = 1; colorAttachmentRef.attachment = 0;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{}; VkAttachmentReference depthAttachmentRef{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; depthAttachmentRef.attachment = 1;
subpass.colorAttachmentCount = 1; depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
VkSubpassDependency dependency{}; VkSubpassDescription subpass{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
dependency.dstSubpass = 0; subpass.colorAttachmentCount = 1;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; subpass.pColorAttachments = &colorAttachmentRef;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; subpass.pDepthStencilAttachment = &depthAttachmentRef;
dependency.srcAccessMask = 0;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment}; VkSubpassDependency dependency{};
VkRenderPassCreateInfo renderPassCreateInfo{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; dependency.dstSubpass = 0;
renderPassCreateInfo.attachmentCount = attachments.size(); dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
renderPassCreateInfo.pAttachments = attachments.data(); dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
renderPassCreateInfo.subpassCount = 1; dependency.srcAccessMask = 0;
renderPassCreateInfo.pSubpasses = &subpass; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
renderPassCreateInfo.dependencyCount = 1;
renderPassCreateInfo.pDependencies = &dependency;
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass"); std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment};
} VkRenderPassCreateInfo renderPassCreateInfo{};
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.attachmentCount = attachments.size();
renderPassCreateInfo.pAttachments = attachments.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpass;
renderPassCreateInfo.dependencyCount = 1;
renderPassCreateInfo.pDependencies = &dependency;
void SwapChain::InitializeFramebuffers() CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "InitializeRenderPass : Failed to initialze render pass");
{ }
framebuffers.resize(images.size());
for (size_t i = 0; i < imageViews.size(); ++i) void SwapChain::InitializeFramebuffers()
{ {
std::vector<VkImageView> attachments{imageViews[i], depthImage->GetImageView()}; framebuffers.resize(images.size());
VkFramebufferCreateInfo createInfo{}; for (size_t i = 0; i < imageViews.size(); ++i)
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; {
createInfo.renderPass = renderPass; std::vector<VkImageView> attachments{imageViews[i], depthAttachment->GetImageView()};
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = extent.width;
createInfo.height = extent.height;
createInfo.layers = 1;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer"); VkFramebufferCreateInfo createInfo{};
} createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
} createInfo.renderPass = renderPass;
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = extent.width;
createInfo.height = extent.height;
createInfo.layers = 1;
void SwapChain::Destroy() CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer");
{ }
for (auto&& framebuffer : framebuffers) }
{
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
}
for (auto&& swapChainImageView : imageViews)
{
vkDestroyImageView(instance.GetDevice(), swapChainImageView, nullptr);
}
vkDestroySwapchainKHR(instance.GetDevice(), handle, nullptr);
}
VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) void SwapChain::Destroy()
{ {
for (auto&& availableFormat : availableFormats) for (auto&& framebuffer : framebuffers)
{ {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
{ }
return availableFormat; for (auto&& swapChainImageView : imageViews)
} {
} vkDestroyImageView(instance.GetDevice(), swapChainImageView, nullptr);
return availableFormats[0]; }
} vkDestroySwapchainKHR(instance.GetDevice(), handle, nullptr);
}
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
{ {
return VK_PRESENT_MODE_FIFO_KHR; for (auto&& availableFormat : availableFormats)
for (auto&& availablePresentMode : availablePresentModes) {
{ if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
{ return availableFormat;
return availablePresentMode; }
} }
} return availableFormats[0];
}
// VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
return VK_PRESENT_MODE_FIFO_KHR; {
} return VK_PRESENT_MODE_FIFO_KHR;
for (auto&& availablePresentMode : availablePresentModes)
{
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
{
return availablePresentMode;
}
}
VkExtent2D SwapChain::SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities) // VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
{ return VK_PRESENT_MODE_FIFO_KHR;
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) }
return capabilities.currentExtent;
int width, height; VkExtent2D SwapChain::SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
glfwGetFramebufferSize(window, &width, &height); {
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return capabilities.currentExtent;
VkExtent2D extent{width, height}; int width, height;
extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); glfwGetFramebufferSize(window, &width, &height);
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return extent; VkExtent2D extent{width, height};
} extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return extent;
}
} }
+3 -3
View File
@@ -10,7 +10,7 @@ namespace Copium
{ {
class Instance; class Instance;
class CommandBuffer; class CommandBuffer;
class Texture2D; class DepthAttachment;
struct SwapChainSupportDetails struct SwapChainSupportDetails
{ {
@@ -32,7 +32,7 @@ namespace Copium
VkRenderPass renderPass; VkRenderPass renderPass;
VkFormat imageFormat; VkFormat imageFormat;
VkExtent2D extent; VkExtent2D extent;
std::unique_ptr<Texture2D> depthImage; std::unique_ptr<DepthAttachment> depthAttachment;
std::vector<VkImageView> imageViews; std::vector<VkImageView> imageViews;
std::vector<VkImage> images; std::vector<VkImage> images;
std::vector<VkFramebuffer> framebuffers; std::vector<VkFramebuffer> framebuffers;
@@ -56,7 +56,7 @@ namespace Copium
private: private:
void Initialize(); void Initialize();
void InitializeImageViews(); void InitializeImageViews();
void InitializeDepthBuffer(); void InitializeDepthAttachment();
void InitializeRenderPass(); void InitializeRenderPass();
void InitializeFramebuffers(); void InitializeFramebuffers();
void Destroy(); void Destroy();
+10 -110
View File
@@ -6,28 +6,16 @@
namespace Copium namespace Copium
{ {
Texture2D::Texture2D(Instance& instance, const std::string& filename) Texture2D::Texture2D(Instance& instance, const std::string& filename)
: instance{instance}, type{Type::Static}, format{Format::Image} : Sampler{instance}
{ {
InitializeTextureImage(filename); InitializeTextureImage(filename);
InitializeSampler();
}
Texture2D::Texture2D(Instance& instance, int width, int height, Type type, Format format)
: instance{instance}, type{type}, format{format}
{
InitializeTexture(width, height);
InitializeSampler();
} }
Texture2D::~Texture2D() Texture2D::~Texture2D()
{ {
for (auto&& image : images) vkDestroyImage(instance.GetDevice(), image, nullptr);
vkDestroyImage(instance.GetDevice(), image, nullptr); vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
for (auto&& imageMemory : imageMemories) vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
for (auto&& imageView : imageViews)
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
} }
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const
@@ -35,34 +23,11 @@ namespace Copium
VkDescriptorImageInfo imageInfo{}; VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler; imageInfo.sampler = sampler;
imageInfo.imageView = imageView;
switch (type) {
case Type::Static:
imageInfo.imageView = imageViews.front();
break;
case Type::Dynamic:
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for dynamic texture");
imageInfo.imageView = imageViews[index];
break;
default:
CP_ABORT("GetDescriptorImageInfo : Unreachable switch case");
}
return imageInfo; return imageInfo;
} }
VkImageView Texture2D::GetImageView() const
{
CP_ASSERT(type == Type::Static, "GetImageView : Texture2D is not static");
return imageViews.front();
}
VkImageView Texture2D::GetImageView(int index)
{
CP_ASSERT(type == Type::Dynamic && index >= 0 && index < imageViews.size(), "GetImageView : Texture2D is not dynamic or index out of bound for SystemTexture");
return imageViews[index];
}
void Texture2D::InitializeTextureImage(const std::string& filename) void Texture2D::InitializeTextureImage(const std::string& filename)
{ {
int texWidth; int texWidth;
@@ -79,75 +44,10 @@ namespace Copium
stagingBuffer.Unmap(); stagingBuffer.Unmap();
stbi_image_free(pixels); stbi_image_free(pixels);
images.resize(1); 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);
imageMemories.resize(1); Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
imageViews.resize(1); Image::CopyBufferToImage(instance, stagingBuffer, image, texWidth, texHeight);
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, &images.front(), &imageMemories.front()); Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); imageView = Image::InitializeImageView(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CopyBufferToImage(instance, stagingBuffer, images.front(), texWidth, texHeight);
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
imageViews[0] = Image::InitializeImageView(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
}
void Texture2D::InitializeTexture(int width, int height)
{
int count = 1;
if (type == Type::Dynamic)
count = instance.GetMaxFramesInFlight();
images.resize(count);
imageMemories.resize(count);
imageViews.resize(count);
for (size_t i = 0; i < images.size(); i++)
{
switch (format)
{
case Format::Color:
{
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
// Image::TransitionImageLayout(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
break;
}
case Format::Depth:
{
VkFormat depthFormat = Image::SelectDepthFormat(instance);
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
// Image::TransitionImageLayout(instance, images[i], depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
imageViews[i] = Image::InitializeImageView(instance, images[i], depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
break;
}
case Format::Image:
{
CP_ABORT("InitializeTexture : Image format currently not supported");
}
default:
CP_ABORT("InitializeTexture : Unreachable switch case");
}
}
}
void Texture2D::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), "InitializeSampler : Failed to initialize texture sampler");
} }
} }
+7 -27
View File
@@ -5,43 +5,23 @@
#include "Common.h" #include "Common.h"
#include "Image.h" #include "Image.h"
#include "Instance.h" #include "Instance.h"
#include "Sampler.h"
namespace Copium namespace Copium
{ {
// TODO: Separate Texture2D and Framebuffer Attachments class Texture2D : public Sampler
class Texture2D
{ {
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D); CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
public:
enum class Type
{
Static, Dynamic
};
enum class Format
{
Image, Color, Depth
};
private: private:
Instance& instance; VkImage image;
VkDeviceMemory imageMemory;
std::vector<VkImage> images; VkImageView imageView;
std::vector<VkDeviceMemory> imageMemories;
std::vector<VkImageView> imageViews;
VkSampler sampler;
Type type;
Format format;
public: public:
Texture2D(Instance& instance, const std::string& filename); Texture2D(Instance& instance, const std::string& filename);
Texture2D(Instance& instance, int width, int height, Type type, Format format); ~Texture2D() override;
~Texture2D();
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const; VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
VkImageView GetImageView() const;
VkImageView GetImageView(int index);
private: private:
void InitializeTextureImage(const std::string& filename); void InitializeTextureImage(const std::string& filename);
void InitializeTexture(int width, int height);
void InitializeSampler();
}; };
} }
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Copium
template <typename T> template <typename T>
void Update(const T& t) void Update(const T& t)
{ {
CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize()); CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Update : Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize());
Buffer::Update((void*)&t, instance.GetFlightIndex()); Buffer::Update((void*)&t, instance.GetFlightIndex());
} }
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Copium
template <typename T> template <typename T>
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset) void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset)
{ {
CP_ASSERT(binding <= bindings.size(), "Attribute binding must less than or be equal to the amount of current bindings"); CP_ASSERT(binding <= bindings.size(), "AddAttribute : Attribute binding must less than or be equal to the amount of current bindings");
if (binding == bindings.size()) if (binding == bindings.size())
AddLayout(binding, sizeof(T)); AddLayout(binding, sizeof(T));
+1 -1
View File
@@ -16,7 +16,7 @@ int main()
glfwPollEvents(); glfwPollEvents();
if (timer.Elapsed() >= 1.0) if (timer.Elapsed() >= 1.0)
{ {
CP_DEBUG("%d fps", frames); CP_DEBUG("main : %d fps", frames);
frames = 0; frames = 0;
timer.Start(); timer.Start();
} }