Add namespace to all classes

This commit is contained in:
Thraix
2023-02-05 10:52:27 +01:00
parent 708b81c571
commit 88979a5ab9
32 changed files with 2611 additions and 2535 deletions
-1
View File
@@ -192,7 +192,6 @@
<ClInclude Include="src\VertexBuffer.h" />
<ClInclude Include="src\VertexDescriptor.h" />
<ClInclude Include="src\VulkanException.h" />
<ClInclude Include="src\Window.h" />
<ClInclude Include="src\VertexPassthrough.h" />
</ItemGroup>
<ItemGroup>
-3
View File
@@ -50,9 +50,6 @@
<ClInclude Include="src\Instance.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Window.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
+239
View File
@@ -0,0 +1,239 @@
#pragma once
#include "Buffer.h"
#include "DescriptorPool.h"
#include "DescriptorSet.h"
#include "Framebuffer.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 "VertexPassthrough.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <optional>
#include <set>
#include <vector>
namespace Copium
{
const std::vector<Vertex> vertices = {
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,
4, 5, 6, 6, 7, 4
};
const std::vector<VertexPassthrough> verticesPassthrough = {
VertexPassthrough{{-1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, 1.0f}},
VertexPassthrough{{-1.0f, 1.0f}},
};
const std::vector<uint16_t> indicesPassthrough = {
0, 1, 2, 2, 3, 0,
};
struct alignas(64) ShaderUniform
{
alignas(16) glm::mat4 projection;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 model;
alignas(16) glm::vec3 lightPos;
};
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<CommandBuffer> commandBuffer;
std::unique_ptr<Framebuffer> framebuffer;
std::unique_ptr<Pipeline> graphicsPipelinePassthrough;
std::unique_ptr<VertexBuffer> vertexBufferPassthrough;
std::unique_ptr<IndexBuffer> indexBufferPassthrough;
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
public:
Application()
{
InitializeInstance();
InitializeFrameBuffer();
InitializeGraphicsPipeline();
InitializeTextureSampler();
InitializeUniformBuffer();
InitializeDescriptorSets();
InitializeVertexBuffer();
InitializeIndexBuffer();
InitializeCommandBuffer();
}
~Application()
{
vkDeviceWaitIdle(instance->GetDevice());
}
Application(Application&&) = delete;
Application(const Application&) = delete;
Application& operator=(Application&&) = delete;
Application& operator=(const Application&) = delete;
bool Update()
{
if (!instance->BeginPresent())
return true;
RecordCommandBuffer();
commandBuffer->SubmitAsGraphicsQueue();
return instance->EndPresent();
}
private:
void InitializeInstance()
{
instance = std::make_unique<Instance>("Copium Engine");
}
void InitializeFrameBuffer()
{
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
}
void InitializeTextureSampler()
{
texture2D = std::make_unique<Texture2D>(*instance, "res/textures/texture.png");
}
void InitializeUniformBuffer()
{
shaderUniformBuffer = std::make_unique<UniformBuffer>(*instance, sizeof(ShaderUniform));
}
void InitializeDescriptorSets()
{
descriptorPool = std::make_unique<DescriptorPool>(*instance);
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
descriptorSet->AddTexture2D(*texture2D, 1);
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0);
}
void InitializeGraphicsPipeline()
{
PipelineCreator creator{framebuffer->GetRenderPass(), "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);
PipelineCreator creatorPassthrough{instance->GetSwapChain().GetRenderPass(), "res/shaders/passthrough.vert", "res/shaders/passthrough.frag"};
creatorPassthrough.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
creatorPassthrough.SetVertexDescriptor(VertexPassthrough::GetDescriptor());
creatorPassthrough.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipelinePassthrough = std::make_unique<Pipeline>(*instance, creatorPassthrough);
}
void InitializeVertexBuffer()
{
vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size());
vertexBuffer->Update(0, (void*)vertices.data());
vertexBufferPassthrough = std::make_unique<VertexBuffer>(*instance, VertexPassthrough::GetDescriptor(), verticesPassthrough.size());
vertexBufferPassthrough->Update(0, (void*)verticesPassthrough.data());
}
void InitializeIndexBuffer()
{
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
indexBuffer->UpdateStaging((void*)indices.data());
indexBufferPassthrough = std::make_unique<IndexBuffer>(*instance, indicesPassthrough.size());
indexBufferPassthrough->UpdateStaging((void*)indicesPassthrough.data());
}
void InitializeCommandBuffer()
{
commandBuffer = std::make_unique<CommandBuffer>(*instance, CommandBuffer::Type::Dynamic);
}
void RecordCommandBuffer()
{
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);
graphicsPipeline->Bind(*commandBuffer);
UpdateUniformBuffer();
vertexBuffer->Bind(*commandBuffer);
indexBuffer->Bind(*commandBuffer);
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
indexBuffer->Draw(*commandBuffer);
framebuffer->Unbind(*commandBuffer);
instance->GetSwapChain().BeginFrameBuffer(*commandBuffer);
graphicsPipelinePassthrough->Bind(*commandBuffer);
graphicsPipelinePassthrough->SetDescriptorSet(0, *descriptorSetPassthrough);
graphicsPipelinePassthrough->BindDescriptorSets(commandBuffer->GetHandle());
vertexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Draw(*commandBuffer);
instance->GetSwapChain().EndFrameBuffer(*commandBuffer);
commandBuffer->End();
}
void UpdateUniformBuffer()
{
static Timer startTimer;
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.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);
}
};
}
+142 -139
View File
@@ -5,166 +5,169 @@
#include <optional>
#include <vulkan/vulkan.hpp>
class Buffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(Buffer);
protected:
Instance& instance;
VkDeviceMemory memory;
VkBuffer handle;
VkDeviceSize size;
int count;
void* mappedData = nullptr;
public:
Buffer(Instance& instance, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDeviceSize size, int count)
: instance{instance}, size{size}, count{count}
{
VkBufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = size * (VkDeviceSize)count;
createInfo.usage = usage;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
CP_VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer");
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &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, &memory), "Failed to allocate buffer memory");
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
}
virtual ~Buffer()
class Buffer
{
vkFreeMemory(instance.GetDevice(), memory, nullptr);
vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
}
CP_DELETE_COPY_AND_MOVE_CTOR(Buffer);
protected:
Instance& instance;
void Update(void* indexData, int index)
{
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
VkDeviceMemory memory;
VkBuffer handle;
VkDeviceSize size;
int count;
if (mappedData == nullptr)
void* mappedData = nullptr;
public:
Buffer(Instance& instance, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDeviceSize size, int count)
: instance{instance}, size{size}, count{count}
{
void* data;
vkMapMemory(instance.GetDevice(), memory, index * size, size, 0, &data);
memcpy(data, indexData, size);
VkBufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = size * (VkDeviceSize)count;
createInfo.usage = usage;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
CP_VK_ASSERT(vkCreateBuffer(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize buffer");
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &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, &memory), "Failed to allocate buffer memory");
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
}
virtual ~Buffer()
{
vkFreeMemory(instance.GetDevice(), memory, nullptr);
vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
}
void Update(void* indexData, int index)
{
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
if (mappedData == nullptr)
{
void* data;
vkMapMemory(instance.GetDevice(), memory, index * size, size, 0, &data);
memcpy(data, indexData, size);
vkUnmapMemory(instance.GetDevice(), memory);
}
else
{
memcpy((char*)mappedData + index * size, indexData, size);
}
}
void UpdateStaging(void* data)
{
VkDeviceSize bufferSize = size * count;
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
stagingBuffer.Update(data, 0);
CopyBuffer(instance, stagingBuffer, *this, 0, bufferSize);
}
void UpdateStaging(void* data, VkDeviceSize offset, VkDeviceSize size)
{
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, 1};
stagingBuffer.Update(data, 0);
CopyBuffer(instance, stagingBuffer, *this, offset, size);
}
void* Map()
{
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
return mappedData;
}
void Unmap()
{
CP_ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer");
vkUnmapMemory(instance.GetDevice(), memory);
mappedData = nullptr;
}
else
virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); };
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
{
memcpy((char*)mappedData + index * size, indexData, size);
VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &handle, &offset);
}
}
void UpdateStaging(void* data)
{
VkDeviceSize bufferSize = size * count;
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
void BindAsIndexBuffer(VkCommandBuffer commandBuffer)
{
// TODO: Maybe don't assume that indices are uint16?
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
}
stagingBuffer.Update(data, 0);
VkBuffer GetHandle() const
{
return handle;
}
CopyBuffer(instance, stagingBuffer, *this, 0, bufferSize);
}
VkDeviceSize GetSize() const
{
return size;
}
void UpdateStaging(void* data, VkDeviceSize offset, VkDeviceSize size)
{
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, 1};
VkDeviceSize GetPosition(int index) const
{
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
return size * (VkDeviceSize)index;
}
stagingBuffer.Update(data, 0);
static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer, VkDeviceSize offset, VkDeviceSize size)
{
VkCommandBufferAllocateInfo allocateInfo{};
CopyBuffer(instance, stagingBuffer, *this, offset, size);
}
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandPool = instance.GetCommandPool();
allocateInfo.commandBufferCount = 1;
void* Map()
{
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
return mappedData;
}
VkCommandBuffer commandBuffer;
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer");
void Unmap()
{
CP_ASSERT(mappedData != nullptr, "Unmapping an already unmapped buffer");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkUnmapMemory(instance.GetDevice(), memory);
mappedData = nullptr;
}
vkBeginCommandBuffer(commandBuffer, &beginInfo);
virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); };
VkBufferCopy bufferCopy{};
bufferCopy.dstOffset = offset;
bufferCopy.srcOffset = 0;
bufferCopy.size = size;
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
{
VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &handle, &offset);
}
vkCmdCopyBuffer(commandBuffer, srcBuffer.GetHandle(), dstBuffer.GetHandle(), 1, &bufferCopy);
void BindAsIndexBuffer(VkCommandBuffer commandBuffer)
{
// TODO: Maybe don't assume that indices are uint16?
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
}
vkEndCommandBuffer(commandBuffer);
VkBuffer GetHandle() const
{
return handle;
}
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
VkDeviceSize GetSize() const
{
return size;
}
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(instance.GetGraphicsQueue());
VkDeviceSize GetPosition(int index) const
{
CP_ASSERT(index >= 0 && index < count, "index is outside of the buffer");
return size * (VkDeviceSize)index;
}
static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer, VkDeviceSize offset, VkDeviceSize size)
{
VkCommandBufferAllocateInfo allocateInfo{};
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandPool = instance.GetCommandPool();
allocateInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
CP_VK_ASSERT(vkAllocateCommandBuffers(instance.GetDevice(), &allocateInfo, &commandBuffer), "Failed to initialize command buffer");
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
VkBufferCopy bufferCopy{};
bufferCopy.dstOffset = offset;
bufferCopy.srcOffset = 0;
bufferCopy.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer.GetHandle(), dstBuffer.GetHandle(), 1, &bufferCopy);
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);
}
};
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), 1, &commandBuffer);
}
};
}
+86 -83
View File
@@ -4,96 +4,99 @@
#include "Instance.h"
#include <vulkan/vulkan.hpp>
enum class CommandBufferType
namespace Copium
{
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}
class CommandBuffer
{
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());
}
operator VkCommandBuffer() const
{
return currentCommandBuffer;
}
// 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)
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBuffer);
public:
enum class 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);
SingleUse, Dynamic
};
private:
Instance& instance;
std::vector<VkCommandBuffer> commandBuffers;
const Type type;
VkCommandBuffer currentCommandBuffer{VK_NULL_HANDLE};
public:
CommandBuffer(Instance& instance, Type type)
: instance{instance}, type{type}
{
if (type == Type::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");
}
vkResetCommandBuffer(currentCommandBuffer, 0);
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Failed to begin command buffer");
}
~CommandBuffer()
{
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
}
void End()
{
vkEndCommandBuffer(currentCommandBuffer);
}
operator VkCommandBuffer() const
{
return currentCommandBuffer;
}
void Submit()
{
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &currentCommandBuffer;
// 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 Type::SingleUse:
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
currentCommandBuffer = commandBuffers.front();
break;
case Type::Dynamic:
currentCommandBuffer = commandBuffers[instance.GetFlightIndex()];
break;
default:
CP_WARN("Unhandled enum case: %d", (int)type);
}
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
// TODO: if singleUse?
vkQueueWaitIdle(instance.GetGraphicsQueue());
}
vkResetCommandBuffer(currentCommandBuffer, 0);
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Failed to begin command buffer");
}
void SubmitAsGraphicsQueue()
{
instance.SubmitGraphicsQueue({currentCommandBuffer});
}
void End()
{
vkEndCommandBuffer(currentCommandBuffer);
}
VkCommandBuffer GetHandle() const
{
return 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() const
{
return currentCommandBuffer;
}
};
}
+16 -13
View File
@@ -3,19 +3,22 @@
#include "Common.h"
#include "CommandBuffer.h"
class CommandBufferScoped : public CommandBuffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBufferScoped);
public:
CommandBufferScoped(Instance& instance)
: CommandBuffer{instance, CommandBufferType::SingleUse}
class CommandBufferScoped : public CommandBuffer
{
CommandBuffer::Begin();
}
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBufferScoped);
public:
CommandBufferScoped(Instance& instance)
: CommandBuffer{instance, Type::SingleUse}
{
CommandBuffer::Begin();
}
~CommandBufferScoped()
{
CommandBuffer::End();
CommandBuffer::Submit();
}
};
~CommandBufferScoped()
{
CommandBuffer::End();
CommandBuffer::Submit();
}
};
}
+21 -19
View File
@@ -3,29 +3,29 @@
#include "VulkanException.h"
#include <iostream>
#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_TERM_RED "\x1B[31m"
#define CP_TERM_GREEN "\x1B[32m"
#define CP_TERM_YELLOW "\x1B[33m"
#define CP_TERM_GRAY "\x1B[90m"
#define CP_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 << 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
#define CP_DEBUG(format, ...) std::cout << CP_TERM_GRAY << "[DBG] " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_INFO(format, ...) std::cout << "[INF] " << Copium::StringFormat(format, __VA_ARGS__) << std::endl
#define CP_WARN(format, ...) std::cout << CP_TERM_YELLOW << "[WRN] " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_ERR(format, ...) std::cout << CP_TERM_RED << "[ERR] " << Copium::StringFormat(format, __VA_ARGS__) << CP_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_DEBUG_CONT(format, ...) std::cout << CP_TERM_GRAY << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_INFO_CONT(format, ...) std::cout << " " << Copium::StringFormat(format, __VA_ARGS__) << std::endl
#define CP_WARN_CONT(format, ...) std::cout << CP_TERM_YELLOW << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_ERR_CONT(format, ...) std::cout << CP_TERM_RED << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
#define CP_ABORT(format, ...) \
do \
{ \
CP_ERR(format, __VA_ARGS__); \
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
throw std::runtime_error(Copium::StringFormat(format, __VA_ARGS__)); \
} while(false)
#define CP_ASSERT(Function, format, ...) \
do \
@@ -33,7 +33,7 @@
if(!(Function)) \
{ \
CP_ERR(format, __VA_ARGS__); \
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
throw std::runtime_error(Copium::StringFormat(format, __VA_ARGS__)); \
} \
} while(false)
#define CP_VK_ASSERT(Function, format, ...) \
@@ -42,7 +42,7 @@
if(Function != VK_SUCCESS) \
{ \
CP_ERR(format, __VA_ARGS__); \
throw VulkanException(StringFormat(format, __VA_ARGS__)); \
throw VulkanException(Copium::StringFormat(format, __VA_ARGS__)); \
} \
} while(false)
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
@@ -51,13 +51,15 @@
ClassName& operator=(ClassName&&) = delete; \
ClassName& operator=(const ClassName&) = delete
template<typename ... Args>
std::string StringFormat(const std::string& format, Args... args)
namespace Copium
{
template<typename ... Args>
std::string StringFormat(const std::string& format, Args... args)
{
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
CP_ASSERT(size > 0, "Error during formatting");
std::unique_ptr<char[]> buf(new char[size]);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1);
}
}
+78 -75
View File
@@ -1,88 +1,91 @@
#pragma once
#include "Common.h"
class DebugMessenger
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
public:
VkInstance instance;
VkDebugUtilsMessengerEXT debugMessenger;
DebugMessenger(VkInstance instance)
: instance{instance}
class DebugMessenger
{
#ifndef NDEBUG
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = DebugCallback;
createInfo.pUserData = nullptr;
CP_VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "Failed to initialze debug messenger");
#endif
}
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
public:
VkInstance instance;
VkDebugUtilsMessengerEXT debugMessenger;
~DebugMessenger()
{
#ifndef NDEBUG
vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
#endif
}
static void AddRequiredExtensions(std::vector<const char*>* extensions)
{
#ifndef NDEBUG
extensions->emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
}
static void AddRequiredLayers(std::vector<const char*>* layers)
{
#ifndef NDEBUG
layers->emplace_back("VK_LAYER_KHRONOS_validation");
#endif
}
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
DebugMessenger(VkInstance instance)
: instance{instance}
{
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
#ifndef NDEBUG
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = DebugCallback;
createInfo.pUserData = nullptr;
CP_VK_ASSERT(vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger), "Failed to initialze debug messenger");
#endif
}
~DebugMessenger()
{
#ifndef NDEBUG
vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
#endif
}
static void AddRequiredExtensions(std::vector<const char*>* extensions)
{
#ifndef NDEBUG
extensions->emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
}
static void AddRequiredLayers(std::vector<const char*>* layers)
{
#ifndef NDEBUG
layers->emplace_back("VK_LAYER_KHRONOS_validation");
#endif
}
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{
CP_ERR(pCallbackData->pMessage);
throw VulkanException(pCallbackData->pMessage);
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{
CP_ERR(pCallbackData->pMessage);
throw VulkanException(pCallbackData->pMessage);
}
CP_WARN(pCallbackData->pMessage);
}
CP_WARN(pCallbackData->pMessage);
return VK_FALSE;
}
return VK_FALSE;
}
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDebugUtilsMessengerEXT* pDebugMessenger)
{
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (func != nullptr)
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
VkDebugUtilsMessengerEXT debugMessenger,
const VkAllocationCallbacks* pAllocator) {
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
if (func != nullptr) {
func(instance, debugMessenger, pAllocator);
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);
}
}
};
}
+48 -45
View File
@@ -4,58 +4,61 @@
#include "Instance.h"
#include <vulkan/vulkan.hpp>
class DescriptorPool final
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorPool);
private:
Instance& instance;
VkDescriptorPool descriptorPool;
static const int DESCRIPTOR_SET_COUNT = 100;
public:
DescriptorPool(Instance& instance)
: instance{instance}
class DescriptorPool final
{
std::vector<VkDescriptorPoolSize> poolSizes{2};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorPool);
private:
Instance& instance;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
poolSizes[1].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
VkDescriptorPool descriptorPool;
static const int DESCRIPTOR_SET_COUNT = 100;
public:
DescriptorPool(Instance& instance)
: instance{instance}
{
std::vector<VkDescriptorPoolSize> poolSizes{2};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
VkDescriptorPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
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;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
poolSizes[1].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
}
VkDescriptorPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
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;
~DescriptorPool()
{
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
}
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
}
std::vector<VkDescriptorSet> AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout)
{
std::vector<VkDescriptorSet> descriptorSets;
std::vector<VkDescriptorSetLayout> layouts{static_cast<size_t>(instance.GetMaxFramesInFlight()), descriptorSetLayout};
VkDescriptorSetAllocateInfo allocateInfo{};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = descriptorPool;
allocateInfo.descriptorSetCount = instance.GetMaxFramesInFlight();
allocateInfo.pSetLayouts = layouts.data();
~DescriptorPool()
{
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
}
descriptorSets.resize(instance.GetMaxFramesInFlight());
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
std::vector<VkDescriptorSet> AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout)
{
std::vector<VkDescriptorSet> descriptorSets;
std::vector<VkDescriptorSetLayout> layouts{static_cast<size_t>(instance.GetMaxFramesInFlight()), descriptorSetLayout};
VkDescriptorSetAllocateInfo allocateInfo{};
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocateInfo.descriptorPool = descriptorPool;
allocateInfo.descriptorSetCount = instance.GetMaxFramesInFlight();
allocateInfo.pSetLayouts = layouts.data();
return descriptorSets;
}
descriptorSets.resize(instance.GetMaxFramesInFlight());
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
{
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
}
};
return descriptorSets;
}
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
{
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
}
};
}
+59 -56
View File
@@ -6,67 +6,70 @@
#include "UniformBuffer.h"
#include <vulkan/vulkan.hpp>
class DescriptorSet final
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
private:
Instance& instance;
DescriptorPool& descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> descriptorSets;
public:
DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout)
: instance{instance}, descriptorPool{descriptorPool}, descriptorSetLayout{descriptorSetLayout}
class DescriptorSet final
{
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
}
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
private:
Instance& instance;
DescriptorPool& descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
~DescriptorSet()
{
descriptorPool.FreeDescriptorSets(descriptorSets);
}
std::vector<VkDescriptorSet> descriptorSets;
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
{
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
VkDescriptorBufferInfo bufferInfo = uniformBuffer.GetDescriptorBufferInfo(i);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.pImageInfo = nullptr;
descriptorWrite.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
public:
DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout)
: instance{instance}, descriptorPool{descriptorPool}, descriptorSetLayout{descriptorSetLayout}
{
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
}
}
void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
{
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = nullptr;
descriptorWrite.pImageInfo = &imageInfo;
descriptorWrite.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
~DescriptorSet()
{
descriptorPool.FreeDescriptorSets(descriptorSets);
}
}
VkDescriptorSet GetHandle() const
{
return descriptorSets[instance.GetFlightIndex()];
}
};
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
{
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
VkDescriptorBufferInfo bufferInfo = uniformBuffer.GetDescriptorBufferInfo(i);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.pImageInfo = nullptr;
descriptorWrite.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
}
}
void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
{
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i);
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = nullptr;
descriptorWrite.pImageInfo = &imageInfo;
descriptorWrite.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
}
}
VkDescriptorSet GetHandle() const
{
return descriptorSets[instance.GetFlightIndex()];
}
};
}
+51 -46
View File
@@ -8,65 +8,70 @@
#include <fstream>
namespace FileSystem
namespace Copium
{
static std::vector<char> ReadFile(const std::string& filename)
class FileSystem
{
std::ifstream file(filename, std::ios::ate | std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file");
FileSystem() = delete;
public:
static std::vector<char> ReadFile(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::vector<char> buffer(fileSize);
size_t fileSize = (size_t)file.tellg();
std::vector<char> buffer(fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
return buffer;
}
return buffer;
}
static std::string ReadFileStr(const std::string& filename)
{
std::ifstream file(filename, std::ios::ate | std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file");
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);
size_t fileSize = (size_t)file.tellg();
std::string buffer;
buffer.resize(fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
return buffer;
}
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");
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());
}
file.write(data.c_str(), data.size());
}
static void WriteFile(const std::string& filename, const char* data, size_t size)
{
std::filesystem::path path{filename};
std::filesystem::create_directories(path.parent_path());
std::ofstream file(filename, std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file");
static void WriteFile(const std::string& filename, const char* data, size_t size)
{
std::filesystem::path path{filename};
std::filesystem::create_directories(path.parent_path());
std::ofstream file(filename, std::ios::binary);
CP_ASSERT(file.is_open(), "Failed to open file");
file.write(data, size);
}
file.write(data, size);
}
static bool FileExists(const std::string& filename)
{
std::ifstream file(filename);
return file.good();
}
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;
}
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;
}
};
}
+162 -159
View File
@@ -7,168 +7,171 @@
#include <vulkan/vulkan.hpp>
// TODO: Add resizing (recreate image, depthImage, framebuffers)
class Framebuffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
private:
Instance& instance;
std::unique_ptr<Texture2D> image;
std::unique_ptr<Texture2D> depthImage;
std::vector<VkFramebuffer> framebuffers;
VkRenderPass renderPass;
uint32_t width;
uint32_t height;
public:
Framebuffer(Instance& instance, uint32_t width, uint32_t height)
: instance{instance}, width{width}, height{height}
// TODO: Add resizing (recreate image, depthImage, framebuffers)
class Framebuffer
{
InitializeImages();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
private:
Instance& instance;
~Framebuffer()
{
for (auto& framebuffer : framebuffers)
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
}
std::unique_ptr<Texture2D> image;
std::unique_ptr<Texture2D> depthImage;
std::vector<VkFramebuffer> framebuffers;
VkRenderPass renderPass;
void Bind(const CommandBuffer& commandBuffer)
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[instance.GetFlightIndex()];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = {width, height};
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void Unbind(const CommandBuffer& commandBuffer)
{
vkCmdEndRenderPass(commandBuffer);
}
VkRenderPass GetRenderPass() const
{
return renderPass;
}
VkFramebuffer GetFramebuffer() const
{
return framebuffers[instance.GetFlightIndex()];
}
const Texture2D& GetTexture2D() const
{
return *image;
}
private:
void InitializeImages()
{
image = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color);
}
void InitializeDepthBuffer()
{
depthImage = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Static, Texture2D::Format::Depth);
}
void InitializeRenderPass()
{
VkAttachmentDescription colorAttachment{};
colorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB;
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_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = Image::SelectDepthFormat(instance);
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;
std::vector<VkSubpassDependency> dependencies{2};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
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 = dependencies.size();
renderPassCreateInfo.pDependencies = dependencies.data();
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "InitializeRenderPass : Failed to initialze render pass");
}
void InitializeFramebuffers()
{
framebuffers.resize(instance.GetMaxFramesInFlight());
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
uint32_t width;
uint32_t height;
public:
Framebuffer(Instance& instance, uint32_t width, uint32_t height)
: instance{instance}, width{width}, height{height}
{
std::vector<VkImageView> attachments{image->GetImageView(i), depthImage->GetImageView()};
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = renderPass;
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = width;
createInfo.height = height;
createInfo.layers = 1;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer");
InitializeImages();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
}
};
~Framebuffer()
{
for (auto& framebuffer : framebuffers)
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
}
void Bind(const CommandBuffer& commandBuffer)
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[instance.GetFlightIndex()];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = {width, height};
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void Unbind(const CommandBuffer& commandBuffer)
{
vkCmdEndRenderPass(commandBuffer);
}
VkRenderPass GetRenderPass() const
{
return renderPass;
}
VkFramebuffer GetFramebuffer() const
{
return framebuffers[instance.GetFlightIndex()];
}
const Texture2D& GetTexture2D() const
{
return *image;
}
private:
void InitializeImages()
{
image = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color);
}
void InitializeDepthBuffer()
{
depthImage = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Static, Texture2D::Format::Depth);
}
void InitializeRenderPass()
{
VkAttachmentDescription colorAttachment{};
colorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB;
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_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = Image::SelectDepthFormat(instance);
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;
std::vector<VkSubpassDependency> dependencies{2};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
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 = dependencies.size();
renderPassCreateInfo.pDependencies = dependencies.data();
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "InitializeRenderPass : Failed to initialze render pass");
}
void InitializeFramebuffers()
{
framebuffers.resize(instance.GetMaxFramesInFlight());
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
{
std::vector<VkImageView> attachments{image->GetImageView(i), depthImage->GetImageView()};
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
createInfo.renderPass = renderPass;
createInfo.attachmentCount = attachments.size();
createInfo.pAttachments = attachments.data();
createInfo.width = width;
createInfo.height = height;
createInfo.layers = 1;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer");
}
}
};
}
+172 -167
View File
@@ -6,177 +6,182 @@
#include "CommandBufferScoped.h"
#include "Instance.h"
class Image
namespace Copium
{
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)
class Image
{
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), "InitializeImage : 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), "InitializeImage : 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), "InitializeImageView : 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 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else
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)
{
CP_ABORT("TransitioinImageLayout : Unsupported layout transition");
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), "InitializeImage : 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), "InitializeImage : Failed to initiallizse image memory");
vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0);
}
vkCmdPipelineBarrier(commandBuffer, 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, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
static VkFormat SelectDepthFormat(Instance& instance)
{
return SelectSupportedFormat(instance, {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);
}
private:
static bool HasStencilComponent(VkFormat format)
{
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
static VkFormat SelectSupportedFormat(Instance& instance, const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
{
for (VkFormat format : candidates)
static VkImageView InitializeImageView(Instance& instance, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
{
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;
}
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), "InitializeImageView : Failed to initialize image view");
return imageView;
}
CP_ABORT("SelectSupportedFormat : Failed to select supported format");
}
};
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 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else
{
CP_ABORT("TransitioinImageLayout : Unsupported layout transition");
}
vkCmdPipelineBarrier(commandBuffer, 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, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
static VkFormat SelectDepthFormat(Instance& instance)
{
return SelectSupportedFormat(instance, {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);
}
private:
static bool HasStencilComponent(VkFormat format)
{
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
static VkFormat SelectSupportedFormat(Instance& instance, 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;
}
}
CP_ABORT("SelectSupportedFormat : Failed to select supported format");
}
};
}
+20 -17
View File
@@ -2,23 +2,26 @@
#include "Buffer.h"
class IndexBuffer : public Buffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(IndexBuffer);
private:
int indexCount;
public:
IndexBuffer(Instance& instance, int indexCount)
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
{}
void Bind(const CommandBuffer& commandBuffer) override
class IndexBuffer : public Buffer
{
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
}
CP_DELETE_COPY_AND_MOVE_CTOR(IndexBuffer);
private:
int indexCount;
public:
IndexBuffer(Instance& instance, int indexCount)
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
{}
void Draw(const CommandBuffer& commandBuffer)
{
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
}
};
void Bind(const CommandBuffer& commandBuffer) override
{
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
}
void Draw(const CommandBuffer& commandBuffer)
{
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
}
};
}
+394 -391
View File
@@ -9,439 +9,442 @@
#include "SwapChain.h"
#include "Timer.h"
class Instance final
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(Instance);
private:
static const int MAX_FRAMES_IN_FLIGHT = 2;
static const int WINDOW_WIDTH = 1920;
static const int WINDOW_HEIGHT = 1080;
VkInstance instance;
GLFWwindow* window;
VkSurfaceKHR surface;
std::unique_ptr<DebugMessenger> debugMessenger;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device;
uint32_t graphicsQueueIndex;
uint32_t presentQueueIndex;
VkQueue graphicsQueue;
VkQueue presentQueue;
std::unique_ptr<SwapChain> swapChain;
int flightIndex;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences;
VkCommandPool commandPool;
bool framebufferResized = false;
int frameCount = 0;
Timer timer;
public:
Instance(const std::string& applicationName)
class Instance final
{
timer.Start();
InitializeWindow(applicationName);
InitializeInstance(applicationName);
InitializeDebugMessenger();
InitializeSurface();
SelectPhysicalDevice();
InitializeLogicalDevice();
InitializeCommandPool();
InitializeSwapChain();
InitializeSyncObjects();
CP_INFO("Initialized Vulkan in %f seconds", timer.Elapsed());
}
CP_DELETE_COPY_AND_MOVE_CTOR(Instance);
private:
static const int MAX_FRAMES_IN_FLIGHT = 2;
static const int WINDOW_WIDTH = 1920;
static const int WINDOW_HEIGHT = 1080;
~Instance()
{
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
VkInstance instance;
GLFWwindow* window;
VkSurfaceKHR surface;
std::unique_ptr<DebugMessenger> debugMessenger;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device;
uint32_t graphicsQueueIndex;
uint32_t presentQueueIndex;
VkQueue graphicsQueue;
VkQueue presentQueue;
std::unique_ptr<SwapChain> swapChain;
int flightIndex;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences;
VkCommandPool commandPool;
bool framebufferResized = false;
int frameCount = 0;
Timer timer;
public:
Instance(const std::string& applicationName)
{
vkDestroyFence(device, inFlightFences[i], nullptr);
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
timer.Start();
InitializeWindow(applicationName);
InitializeInstance(applicationName);
InitializeDebugMessenger();
InitializeSurface();
SelectPhysicalDevice();
InitializeLogicalDevice();
InitializeCommandPool();
InitializeSwapChain();
InitializeSyncObjects();
CP_INFO("Initialized Vulkan in %f seconds", timer.Elapsed());
}
vkDestroyCommandPool(device, commandPool, nullptr);
swapChain.reset();
vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
debugMessenger.reset();
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
}
bool BeginPresent()
{
vkWaitForFences(device, 1, &inFlightFences[flightIndex], VK_TRUE, UINT64_MAX);
if (!swapChain->BeginPresent(imageAvailableSemaphores[flightIndex]))
return false;
vkResetFences(device, 1, &inFlightFences[flightIndex]);
return true;
}
bool EndPresent()
{
swapChain->EndPresent(presentQueue, &renderFinishedSemaphores[flightIndex], framebufferResized);
framebufferResized = false;
flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
return !glfwWindowShouldClose(window);
}
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers)
{
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &imageAvailableSemaphores[flightIndex];
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = commandBuffers.size();
submitInfo.pCommandBuffers = commandBuffers.data();
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderFinishedSemaphores[flightIndex];
CP_VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[flightIndex]), "Failed to submit command buffer");
}
VkInstance GetInstance() const
{
return instance;
}
GLFWwindow* GetWindow() const
{
return window;
}
VkSurfaceKHR GetSurface() const
{
return surface;
}
VkPhysicalDevice GetPhysicalDevice() const
{
return physicalDevice;
}
VkDevice GetDevice() const
{
return device;
}
VkCommandPool GetCommandPool() const
{
return commandPool;
}
VkQueue GetGraphicsQueue() const
{
return graphicsQueue;
}
int GetFlightIndex() const
{
return flightIndex;
}
int GetMaxFramesInFlight() const
{
return MAX_FRAMES_IN_FLIGHT;
}
const SwapChain& GetSwapChain() const
{
return *swapChain;
}
// TODO: Create Device class and move this there
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
{
VkPhysicalDeviceMemoryProperties memoryProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
~Instance()
{
if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
return i;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
{
vkDestroyFence(device, inFlightFences[i], nullptr);
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
}
vkDestroyCommandPool(device, commandPool, nullptr);
swapChain.reset();
vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
debugMessenger.reset();
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
}
throw std::runtime_error("Failed to find suitable memory type");
}
private:
void InitializeWindow(const std::string& applicationName)
{
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
bool BeginPresent()
{
vkWaitForFences(device, 1, &inFlightFences[flightIndex], VK_TRUE, UINT64_MAX);
if (!swapChain->BeginPresent(imageAvailableSemaphores[flightIndex]))
return false;
vkResetFences(device, 1, &inFlightFences[flightIndex]);
return true;
}
bool EndPresent()
{
swapChain->EndPresent(presentQueue, &renderFinishedSemaphores[flightIndex], framebufferResized);
framebufferResized = false;
flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
return !glfwWindowShouldClose(window);
}
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers)
{
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &imageAvailableSemaphores[flightIndex];
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = commandBuffers.size();
submitInfo.pCommandBuffers = commandBuffers.data();
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderFinishedSemaphores[flightIndex];
CP_VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[flightIndex]), "Failed to submit command buffer");
}
VkInstance GetInstance() const
{
return instance;
}
GLFWwindow* GetWindow() const
{
return window;
}
VkSurfaceKHR GetSurface() const
{
return surface;
}
VkPhysicalDevice GetPhysicalDevice() const
{
return physicalDevice;
}
VkDevice GetDevice() const
{
return device;
}
VkCommandPool GetCommandPool() const
{
return commandPool;
}
VkQueue GetGraphicsQueue() const
{
return graphicsQueue;
}
int GetFlightIndex() const
{
return flightIndex;
}
int GetMaxFramesInFlight() const
{
return MAX_FRAMES_IN_FLIGHT;
}
const SwapChain& GetSwapChain() const
{
return *swapChain;
}
// TODO: Create Device class and move this there
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
{
VkPhysicalDeviceMemoryProperties memoryProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
{
if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
return i;
}
throw std::runtime_error("Failed to find suitable memory type");
}
private:
void InitializeWindow(const std::string& applicationName)
{
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
#if defined(FULLSCREEN)
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), glfwGetPrimaryMonitor(), nullptr);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), glfwGetPrimaryMonitor(), nullptr);
#elif defined(BORDERLESS_WINDOWED)
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), nullptr, nullptr);
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), nullptr, nullptr);
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
#else
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
#endif
CP_ASSERT(window, "Failed to initialize glfw window");
CP_ASSERT(window, "Failed to initialize glfw window");
glfwSetWindowUserPointer(window, this);
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
}
void InitializeInstance(const std::string& applicationName)
{
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = applicationName.c_str();
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "Copium Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_1;
std::vector<const char*> requiredExtensions = GetRequiredExtensions();
uint32_t extensionCount;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
CP_INFO("Supported Extensions:");
for (auto&& extension : extensions)
{
CP_INFO_CONT("\t%s", extension.extensionName);
glfwSetWindowUserPointer(window, this);
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
}
std::vector<const char*> layers{};
DebugMessenger::AddRequiredLayers(&layers);
CP_ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = requiredExtensions.size();
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
createInfo.enabledLayerCount = layers.size();
createInfo.ppEnabledLayerNames = layers.data();
CP_VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
}
void InitializeDebugMessenger()
{
debugMessenger = std::make_unique<DebugMessenger>(instance);
}
void InitializeSurface()
{
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
}
void SelectPhysicalDevice()
{
uint32_t deviceCount;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
CP_ASSERT(deviceCount != 0, "No available devices support Vulkan");
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
CP_INFO("Available devices:");
for (auto&& device : devices)
void InitializeInstance(const std::string& applicationName)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
CP_INFO_CONT("\t%s", deviceProperties.deviceName);
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = applicationName.c_str();
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "Copium Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_1;
std::vector<const char*> requiredExtensions = GetRequiredExtensions();
uint32_t extensionCount;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
CP_INFO("Supported Extensions:");
for (auto&& extension : extensions)
{
CP_INFO_CONT("\t%s", extension.extensionName);
}
std::vector<const char*> layers{};
DebugMessenger::AddRequiredLayers(&layers);
CP_ASSERT(CheckLayerSupport(layers), "Some required layers are not supported");
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = requiredExtensions.size();
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
createInfo.enabledLayerCount = layers.size();
createInfo.ppEnabledLayerNames = layers.data();
CP_VK_ASSERT(vkCreateInstance(&createInfo, nullptr, &instance), "Failed to create instance");
}
for (auto&& device : devices)
void InitializeDebugMessenger()
{
if (IsPhysicalDeviceSuitable(device))
debugMessenger = std::make_unique<DebugMessenger>(instance);
}
void InitializeSurface()
{
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "Failed to create Vulkan surface");
}
void SelectPhysicalDevice()
{
uint32_t deviceCount;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
CP_ASSERT(deviceCount != 0, "No available devices support Vulkan");
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
CP_INFO("Available devices:");
for (auto&& device : devices)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
physicalDevice = device;
CP_INFO("Selecting device: %s", deviceProperties.deviceName);
break;
CP_INFO_CONT("\t%s", deviceProperties.deviceName);
}
for (auto&& device : devices)
{
if (IsPhysicalDeviceSuitable(device))
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
physicalDevice = device;
CP_INFO("Selecting device: %s", deviceProperties.deviceName);
break;
}
}
CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
}
void InitializeLogicalDevice()
{
QueueFamiliesQuery query{surface, physicalDevice};
float queuePriority = 1.0f;
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
std::set<uint32_t> uniqueQueueFamilies{query.graphicsFamily.value(), query.presentFamily.value()};
for (auto&& queueFamily : uniqueQueueFamilies)
{
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.emplace_back(queueCreateInfo);
}
std::vector<const char*> deviceExtensions = GetRequiredDeviceExtensions();
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.fillModeNonSolid = VK_TRUE;
deviceFeatures.samplerAnisotropy = VK_TRUE;
VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.queueCreateInfoCount = queueCreateInfos.size();
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledExtensionCount = deviceExtensions.size();
CP_VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
graphicsQueueIndex = query.graphicsFamily.value();
presentQueueIndex = query.presentFamily.value();
vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
vkGetDeviceQueue(device, presentQueueIndex, 0, &presentQueue);
}
void InitializeSwapChain()
{
swapChain = std::make_unique<SwapChain>(*this);
}
void InitializeCommandPool()
{
VkCommandPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
createInfo.queueFamilyIndex = graphicsQueueIndex;
CP_VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
}
void InitializeSyncObjects()
{
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
VkSemaphoreCreateInfo semaphoreCreateInfo{};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
{
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
VkFenceCreateInfo fenceCreateInfo{};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
CP_VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
}
}
CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "Failed to find suitable GPU");
}
void InitializeLogicalDevice()
{
QueueFamiliesQuery query{surface, physicalDevice};
float queuePriority = 1.0f;
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
std::set<uint32_t> uniqueQueueFamilies{query.graphicsFamily.value(), query.presentFamily.value()};
for(auto&& queueFamily : uniqueQueueFamilies)
std::vector<const char*> GetRequiredExtensions()
{
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.emplace_back(queueCreateInfo);
}
std::vector<const char*> deviceExtensions = GetRequiredDeviceExtensions();
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.fillModeNonSolid = VK_TRUE;
deviceFeatures.samplerAnisotropy = VK_TRUE;
VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.queueCreateInfoCount = queueCreateInfos.size();
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledExtensionCount = deviceExtensions.size();
uint32_t glfwExtensionCount;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
CP_VK_ASSERT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to initialize logical device");
std::vector<const char*> extensions{glfwExtensions, glfwExtensions + glfwExtensionCount};
graphicsQueueIndex = query.graphicsFamily.value();
presentQueueIndex = query.presentFamily.value();
vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
vkGetDeviceQueue(device, presentQueueIndex , 0, &presentQueue);
}
debugMessenger->AddRequiredExtensions(&extensions);
void InitializeSwapChain()
{
swapChain = std::make_unique<SwapChain>(*this);
}
void InitializeCommandPool()
{
VkCommandPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
createInfo.queueFamilyIndex = graphicsQueueIndex;
CP_VK_ASSERT(vkCreateCommandPool(device, &createInfo, nullptr, &commandPool), "Failed to initialize command pool");
}
void InitializeSyncObjects()
{
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
VkSemaphoreCreateInfo semaphoreCreateInfo{};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
{
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAvailableSemaphores[i]), "Failed to initialize available image semaphore");
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "Failed to initialize render finished semaphore");
VkFenceCreateInfo fenceCreateInfo{};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
CP_VK_ASSERT(vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]), "Failed to initialize in flight fence");
}
}
std::vector<const char*> GetRequiredExtensions()
{
uint32_t glfwExtensionCount;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions{glfwExtensions, glfwExtensions + glfwExtensionCount};
debugMessenger->AddRequiredExtensions(&extensions);
return extensions;
}
bool CheckLayerSupport(const std::vector<const char*>& layers)
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
CP_INFO("Supported Layers:");
for (auto&& availableLayer : availableLayers)
{
CP_INFO_CONT("\t%s", availableLayer.layerName);
return extensions;
}
for (auto&& layer : layers)
bool CheckLayerSupport(const std::vector<const char*>& layers)
{
bool layerFound = false;
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
CP_INFO("Supported Layers:");
for (auto&& availableLayer : availableLayers)
{
if (std::strcmp(layer, availableLayer.layerName) == 0)
{
layerFound = true;
break;
}
CP_INFO_CONT("\t%s", availableLayer.layerName);
}
if (!layerFound)
return false;
}
return true;
}
bool IsPhysicalDeviceSuitable(VkPhysicalDevice device)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
if (deviceProperties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
return false;
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
if (!deviceFeatures.fillModeNonSolid || !deviceFeatures.samplerAnisotropy)
return false;
QueueFamiliesQuery query{surface, device};
if (!query.AllRequiredFamiliesSupported())
return false;
if (!CheckDeviceExtensionSupport(device))
return false;
SwapChainSupportDetails details{surface, device};
if (!details.Valid())
return false;
return true;
}
bool CheckDeviceExtensionSupport(VkPhysicalDevice device)
{
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data());
for (auto&& requiredExtension : GetRequiredDeviceExtensions())
{
bool found = false;
for (auto&& extension : extensions)
for (auto&& layer : layers)
{
if (std::strcmp(requiredExtension, extension.extensionName) == 0)
bool layerFound = false;
for (auto&& availableLayer : availableLayers)
{
found = true;
break;
if (std::strcmp(layer, availableLayer.layerName) == 0)
{
layerFound = true;
break;
}
}
if (!layerFound)
return false;
}
if (!found)
return false;
return true;
}
return true;
}
std::vector<const char*> GetRequiredDeviceExtensions()
{
return {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
}
bool IsPhysicalDeviceSuitable(VkPhysicalDevice device)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
if (deviceProperties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
return false;
static void FramebufferResizeCallback(GLFWwindow* window, int width, int height)
{
Instance* instance = static_cast<Instance*>(glfwGetWindowUserPointer(window));
instance->framebufferResized = true;
}
};
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
if (!deviceFeatures.fillModeNonSolid || !deviceFeatures.samplerAnisotropy)
return false;
QueueFamiliesQuery query{surface, device};
if (!query.AllRequiredFamiliesSupported())
return false;
if (!CheckDeviceExtensionSupport(device))
return false;
SwapChainSupportDetails details{surface, device};
if (!details.Valid())
return false;
return true;
}
bool CheckDeviceExtensionSupport(VkPhysicalDevice device)
{
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions{extensionCount};
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data());
for (auto&& requiredExtension : GetRequiredDeviceExtensions())
{
bool found = false;
for (auto&& extension : extensions)
{
if (std::strcmp(requiredExtension, extension.extensionName) == 0)
{
found = true;
break;
}
}
if (!found)
return false;
}
return true;
}
std::vector<const char*> GetRequiredDeviceExtensions()
{
return {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
}
static void FramebufferResizeCallback(GLFWwindow* window, int width, int height)
{
Instance* instance = static_cast<Instance*>(glfwGetWindowUserPointer(window));
instance->framebufferResized = true;
}
};
}
+212 -210
View File
@@ -11,246 +11,248 @@
#include <vulkan/vulkan.hpp>
#include <map>
class Pipeline
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(Pipeline);
private:
Instance& instance;
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
std::vector<VkDescriptorSet> boundDescriptorSets;
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
public:
Pipeline(Instance& instance, PipelineCreator creator)
: instance{instance}
class Pipeline
{
InitializeDescriptorSetLayout(creator);
InitializePipeline(creator);
}
CP_DELETE_COPY_AND_MOVE_CTOR(Pipeline);
private:
Instance& instance;
~Pipeline()
{
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
for (auto&& descriptorSetLayout : descriptorSetLayouts)
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
std::vector<VkDescriptorSet> boundDescriptorSets;
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
public:
Pipeline(Instance& instance, PipelineCreator creator)
: instance{instance}
{
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
InitializeDescriptorSetLayout(creator);
InitializePipeline(creator);
}
}
void Bind(const CommandBuffer& commandBuffer)
{
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = instance.GetSwapChain().GetExtent().width;
viewport.height = instance.GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = instance.GetSwapChain().GetExtent();
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
}
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
{
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
{
return descriptorSetLayouts[setIndex];
}
private:
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
{
boundDescriptorSets.resize(creator.descriptorSetLayouts.size());
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
int i = 0;
for (auto&& bindings : creator.descriptorSetLayouts)
~Pipeline()
{
std::vector<VkDescriptorSetLayoutBinding> layoutBindings{bindings.second.size()};
int j = 0;
for (auto&& binding : bindings.second)
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
for (auto&& descriptorSetLayout : descriptorSetLayouts)
{
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++;
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
}
VkDescriptorSetLayoutCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
createInfo.bindingCount = layoutBindings.size();
createInfo.pBindings = layoutBindings.data();
CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayouts[i++]), "Failed to initialize descriptor set layout");
}
}
void InitializePipeline(const PipelineCreator& creator)
{
Shader shader{instance, ShaderType::GlslFile, creator.vertexShader, creator.fragmentShader};
void Bind(const CommandBuffer& commandBuffer)
{
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputCreateInfo.vertexBindingDescriptionCount = creator.vertexDescriptor.GetBindings().size();
vertexInputCreateInfo.pVertexBindingDescriptions = creator.vertexDescriptor.GetBindings().data();
vertexInputCreateInfo.vertexAttributeDescriptionCount = creator.vertexDescriptor.GetAttributes().size();
vertexInputCreateInfo.pVertexAttributeDescriptions = creator.vertexDescriptor.GetAttributes().data();
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);
}
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyCreateInfo.topology = creator.topology;
inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
{
CP_ASSERT(setIndex < boundDescriptorSets.size(), "DescriptorSet index is out of bounds");
boundDescriptorSets[setIndex] = descriptorSet.GetHandle();
}
VkViewport viewport{};
viewport.x = 0;
viewport.y = 0;
viewport.width = instance.GetSwapChain().GetExtent().width;
viewport.height = instance.GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
void BindDescriptorSets(VkCommandBuffer commandBuffer)
{
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, boundDescriptorSets.size(), boundDescriptorSets.data(), 0, nullptr);
}
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = instance.GetSwapChain().GetExtent();
VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const
{
return descriptorSetLayouts[setIndex];
}
std::vector<VkDynamicState> dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
private:
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
{
boundDescriptorSets.resize(creator.descriptorSetLayouts.size());
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
int i = 0;
for (auto&& bindings : creator.descriptorSetLayouts)
{
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++;
}
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{};
dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCreateInfo.dynamicStateCount = dynamicStates.size();
dynamicStateCreateInfo.pDynamicStates = dynamicStates.data();
VkDescriptorSetLayoutCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
createInfo.bindingCount = layoutBindings.size();
createInfo.pBindings = layoutBindings.data();
VkPipelineViewportStateCreateInfo viewportStateCreateInfo{};
viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCreateInfo.viewportCount = 1;
viewportStateCreateInfo.pViewports = &viewport;
viewportStateCreateInfo.scissorCount = 1;
viewportStateCreateInfo.pScissors = &scissor;
CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayouts[i++]), "Failed to initialize descriptor set layout");
}
}
VkPipelineRasterizationStateCreateInfo rasterizerCreateInfo{};
rasterizerCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizerCreateInfo.depthClampEnable = VK_FALSE;
rasterizerCreateInfo.rasterizerDiscardEnable = VK_FALSE;
rasterizerCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizerCreateInfo.lineWidth = 1.0f;
rasterizerCreateInfo.cullMode = creator.cullMode;
rasterizerCreateInfo.frontFace = creator.frontFace;
void InitializePipeline(const PipelineCreator& creator)
{
Shader shader{instance, Shader::Type::GlslFile, creator.vertexShader, creator.fragmentShader};
rasterizerCreateInfo.depthBiasEnable = VK_FALSE;
rasterizerCreateInfo.depthBiasConstantFactor = 0.0f;
rasterizerCreateInfo.depthBiasClamp = 0.0f;
rasterizerCreateInfo.depthBiasSlopeFactor = 0.0f;
VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputCreateInfo.vertexBindingDescriptionCount = creator.vertexDescriptor.GetBindings().size();
vertexInputCreateInfo.pVertexBindingDescriptions = creator.vertexDescriptor.GetBindings().data();
vertexInputCreateInfo.vertexAttributeDescriptionCount = creator.vertexDescriptor.GetAttributes().size();
vertexInputCreateInfo.pVertexAttributeDescriptions = creator.vertexDescriptor.GetAttributes().data();
VkPipelineMultisampleStateCreateInfo multisampleCreateInfo{};
multisampleCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleCreateInfo.sampleShadingEnable = VK_FALSE;
multisampleCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampleCreateInfo.minSampleShading = 1.0f;
multisampleCreateInfo.pSampleMask = nullptr;
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyCreateInfo.topology = creator.topology;
inputAssemblyCreateInfo.primitiveRestartEnable = 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 = {};
VkViewport viewport{};
viewport.x = 0;
viewport.y = 0;
viewport.width = instance.GetSwapChain().GetExtent().width;
viewport.height = instance.GetSwapChain().GetExtent().height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = instance.GetSwapChain().GetExtent();
std::vector<VkDynamicState> dynamicStates = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{};
dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCreateInfo.dynamicStateCount = dynamicStates.size();
dynamicStateCreateInfo.pDynamicStates = dynamicStates.data();
VkPipelineViewportStateCreateInfo viewportStateCreateInfo{};
viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCreateInfo.viewportCount = 1;
viewportStateCreateInfo.pViewports = &viewport;
viewportStateCreateInfo.scissorCount = 1;
viewportStateCreateInfo.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizerCreateInfo{};
rasterizerCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizerCreateInfo.depthClampEnable = VK_FALSE;
rasterizerCreateInfo.rasterizerDiscardEnable = VK_FALSE;
rasterizerCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizerCreateInfo.lineWidth = 1.0f;
rasterizerCreateInfo.cullMode = creator.cullMode;
rasterizerCreateInfo.frontFace = creator.frontFace;
rasterizerCreateInfo.depthBiasEnable = VK_FALSE;
rasterizerCreateInfo.depthBiasConstantFactor = 0.0f;
rasterizerCreateInfo.depthBiasClamp = 0.0f;
rasterizerCreateInfo.depthBiasSlopeFactor = 0.0f;
VkPipelineMultisampleStateCreateInfo multisampleCreateInfo{};
multisampleCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleCreateInfo.sampleShadingEnable = VK_FALSE;
multisampleCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampleCreateInfo.minSampleShading = 1.0f;
multisampleCreateInfo.pSampleMask = nullptr;
multisampleCreateInfo.alphaToCoverageEnable = VK_FALSE;
multisampleCreateInfo.alphaToOneEnable = VK_FALSE;
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 |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendAttachmentState colorBlendAttachment{}; // TODO: Add to PipelineCreator
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo{};
colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendCreateInfo.logicOpEnable = VK_FALSE;
colorBlendCreateInfo.logicOp = VK_LOGIC_OP_COPY;
colorBlendCreateInfo.attachmentCount = 1;
colorBlendCreateInfo.pAttachments = &colorBlendAttachment;
colorBlendCreateInfo.blendConstants[0] = 0.0f;
colorBlendCreateInfo.blendConstants[1] = 0.0f;
colorBlendCreateInfo.blendConstants[2] = 0.0f;
colorBlendCreateInfo.blendConstants[3] = 0.0f;
VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo{};
colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendCreateInfo.logicOpEnable = VK_FALSE;
colorBlendCreateInfo.logicOp = VK_LOGIC_OP_COPY;
colorBlendCreateInfo.attachmentCount = 1;
colorBlendCreateInfo.pAttachments = &colorBlendAttachment;
colorBlendCreateInfo.blendConstants[0] = 0.0f;
colorBlendCreateInfo.blendConstants[1] = 0.0f;
colorBlendCreateInfo.blendConstants[2] = 0.0f;
colorBlendCreateInfo.blendConstants[3] = 0.0f;
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCreateInfo.setLayoutCount = descriptorSetLayouts.size();
pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data();
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCreateInfo.setLayoutCount = descriptorSetLayouts.size();
pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data();
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
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), "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 = shaderStages.size();
graphicsPipelineCreateInfo.pStages = shaderStages.data();
graphicsPipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
graphicsPipelineCreateInfo.pRasterizationState = &rasterizerCreateInfo;
graphicsPipelineCreateInfo.pMultisampleState = &multisampleCreateInfo;
graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilCreateInfo;
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = pipelineLayout;
graphicsPipelineCreateInfo.renderPass = creator.renderPass;
graphicsPipelineCreateInfo.subpass = 0;
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
graphicsPipelineCreateInfo.basePipelineIndex = -1;
const std::vector<VkPipelineShaderStageCreateInfo>& shaderStages = shader.GetShaderStages();
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
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 = &depthStencilCreateInfo;
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = pipelineLayout;
graphicsPipelineCreateInfo.renderPass = creator.renderPass;
graphicsPipelineCreateInfo.subpass = 0;
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
graphicsPipelineCreateInfo.basePipelineIndex = -1;
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "Failed to initialize graphics pipeline");
}
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "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 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");
VkShaderModule shaderModule;
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
return shaderModule;
}
return shaderModule;
}
};
};
}
+52 -49
View File
@@ -6,55 +6,58 @@
#include <vulkan/vulkan.hpp>
#include <map>
class PipelineCreator
namespace Copium
{
struct DescriptorSetBinding
class PipelineCreator
{
uint32_t binding;
VkDescriptorType type;
uint32_t count;
VkShaderStageFlags flags;
struct DescriptorSetBinding
{
uint32_t binding;
VkDescriptorType type;
uint32_t count;
VkShaderStageFlags flags;
};
friend class Pipeline;
private:
std::map<uint32_t, std::vector<DescriptorSetBinding>> descriptorSetLayouts{};
std::string vertexShader;
std::string fragmentShader;
VertexDescriptor vertexDescriptor{};
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
VkRenderPass renderPass = VK_NULL_HANDLE;
public:
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
: vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass}
{}
void SetVertexDescriptor(const VertexDescriptor& descriptor)
{
vertexDescriptor = descriptor;
}
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
{
CP_ASSERT(set <= descriptorSetLayouts.size(), "AddDescriptorSetLayoutBinding : 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)
{
topology = primitiveTopology;
}
void SetCullMode(VkCullModeFlags flags)
{
cullMode = flags;
}
void SetCullFrontFace(VkFrontFace cullFrontFace)
{
frontFace = cullFrontFace;
}
};
friend class Pipeline;
private:
std::map<uint32_t, std::vector<DescriptorSetBinding>> descriptorSetLayouts{};
std::string vertexShader;
std::string fragmentShader;
VertexDescriptor vertexDescriptor{};
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
VkRenderPass renderPass = VK_NULL_HANDLE;
public:
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
: vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass}
{}
void SetVertexDescriptor(const VertexDescriptor& descriptor)
{
vertexDescriptor = descriptor;
}
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
{
CP_ASSERT(set <= descriptorSetLayouts.size(), "AddDescriptorSetLayoutBinding : 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)
{
topology = primitiveTopology;
}
void SetCullMode(VkCullModeFlags flags)
{
cullMode = flags;
}
void SetCullFrontFace(VkFrontFace cullFrontFace)
{
frontFace = cullFrontFace;
}
};
}
+30 -27
View File
@@ -4,38 +4,41 @@
#include <optional>
#include <vector>
struct QueueFamiliesQuery
namespace Copium
{
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device)
struct QueueFamiliesQuery
{
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
int i = 0;
for (auto&& queueFamily : queueFamilies)
QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device)
{
if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
int i = 0;
for (auto&& queueFamily : queueFamilies)
{
graphicsFamily = i;
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
graphicsFamily = i;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (presentSupport)
{
presentFamily = i;
}
i++;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (presentSupport)
{
presentFamily = i;
}
i++;
}
}
bool AllRequiredFamiliesSupported()
{
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
bool AllRequiredFamiliesSupported()
{
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
}
+131 -127
View File
@@ -6,146 +6,150 @@
#include "Common.h"
#include "Instance.h"
enum class ShaderType
namespace Copium
{
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}
class Shader
{
switch (shaderType)
CP_DELETE_COPY_AND_MOVE_CTOR(Shader);
public:
enum class Type
{
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);
GlslFile, GlslCode, SpvFile, SpvCode
};
private:
Instance& instance;
VkShaderModule vertShaderModule;
VkShaderModule fragShaderModule;
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
public:
Shader(Instance& instance, Type type, const std::string& vertexInput, const std::string& fragmentInput)
: instance{instance}
{
switch (type)
{
case Type::GlslCode:
vertShaderModule = InitializeShaderModuleFromGlslCode(vertexInput, shaderc_vertex_shader);
fragShaderModule = InitializeShaderModuleFromGlslCode(fragmentInput, shaderc_fragment_shader);
break;
case Type::GlslFile:
vertShaderModule = InitializeShaderModuleFromGlslFile(vertexInput, shaderc_vertex_shader);
fragShaderModule = InitializeShaderModuleFromGlslFile(fragmentInput, shaderc_fragment_shader);
break;
case Type::SpvCode:
vertShaderModule = InitializeShaderModule(vertexInput);
fragShaderModule = InitializeShaderModule(fragmentInput);
break;
case Type::SpvFile:
vertShaderModule = InitializeShaderModule(FileSystem::ReadFile(vertexInput));
fragShaderModule = InitializeShaderModule(FileSystem::ReadFile(fragmentInput));
break;
default:
CP_ASSERT(false, "Unreachable switch case %d", (int)type);
}
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";
}
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 = ".cache/" + filename + ".spv";
try
~Shader()
{
if (FileSystem::FileExists(spvFilename))
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 type)
{
std::string spvFilename = ".cache/" + filename + ".spv";
try
{
if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename))
if (FileSystem::FileExists(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());
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(), 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());
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));
}
catch (const std::runtime_error& e)
VkShaderModule InitializeShaderModuleFromGlslCode(const std::string& code, shaderc_shader_kind type)
{
CP_WARN("Cached shader file is invalid, recreating it");
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.SetOptimizationLevel(shaderc_optimization_level_size);
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());
std::vector<uint32_t> data{result.cbegin(), result.cend()};
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
}
CP_DEBUG("Compiling shader file: %s", filename.c_str());
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.SetOptimizationLevel(shaderc_optimization_level_size);
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;
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());
VkShaderModule shaderModule;
CP_VK_ASSERT(vkCreateShaderModule(instance.GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
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;
}
};
return shaderModule;
}
};
}
+309 -306
View File
@@ -10,333 +10,336 @@
#include <vulkan/vulkan.h>
#include <vector>
SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice)
namespace Copium
{
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
if (formatCount != 0)
SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice)
{
formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
if (formatCount != 0)
{
formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
}
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
if (presentModeCount != 0)
{
presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
}
}
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
if (presentModeCount != 0)
bool SwapChainSupportDetails::Valid()
{
presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
return !formats.empty() && !presentModes.empty();
}
}
bool SwapChainSupportDetails::Valid()
{
return !formats.empty() && !presentModes.empty();
}
SwapChain::SwapChain(Instance& instance)
: instance{instance}
{
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
SwapChain::~SwapChain()
{
Destroy();
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
}
void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[imageIndex];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = extent;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const
{
vkCmdEndRenderPass(commandBuffer);
}
VkSwapchainKHR SwapChain::GetHandle() const
{
return handle;
}
VkRenderPass SwapChain::GetRenderPass() const
{
return renderPass;
}
VkExtent2D SwapChain::GetExtent() const
{
return extent;
}
VkFramebuffer SwapChain::GetFramebuffer() const
{
return framebuffers[imageIndex];
}
bool SwapChain::BeginPresent(VkSemaphore signalSemaphore)
{
VkResult result = vkAcquireNextImageKHR(instance.GetDevice(), handle, UINT64_MAX, signalSemaphore, VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
SwapChain::SwapChain(Instance& instance)
: instance{instance}
{
Recreate();
return false;
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeRenderPass();
InitializeFramebuffers();
}
return true;
}
void SwapChain::EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized)
{
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = waitSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &handle;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr;
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
SwapChain::~SwapChain()
{
Recreate();
Destroy();
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
}
}
void SwapChain::Recreate()
{
int width = 0;
int height = 0;
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
while (width == 0 || height == 0)
void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const
{
std::vector<VkClearValue> clearValues{2};
clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}};
clearValues[1].depthStencil = {1.0f, 0};
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.framebuffer = framebuffers[imageIndex];
renderPassBeginInfo.renderArea.offset = {0, 0};
renderPassBeginInfo.renderArea.extent = extent;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const
{
vkCmdEndRenderPass(commandBuffer);
}
VkSwapchainKHR SwapChain::GetHandle() const
{
return handle;
}
VkRenderPass SwapChain::GetRenderPass() const
{
return renderPass;
}
VkExtent2D SwapChain::GetExtent() const
{
return extent;
}
VkFramebuffer SwapChain::GetFramebuffer() const
{
return framebuffers[imageIndex];
}
bool SwapChain::BeginPresent(VkSemaphore signalSemaphore)
{
VkResult result = vkAcquireNextImageKHR(instance.GetDevice(), handle, UINT64_MAX, signalSemaphore, VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
{
Recreate();
return false;
}
return true;
}
void SwapChain::EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized)
{
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = waitSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &handle;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr;
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized)
{
Recreate();
}
}
void SwapChain::Recreate()
{
int width = 0;
int height = 0;
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
glfwWaitEvents();
}
vkDeviceWaitIdle(instance.GetDevice());
Destroy();
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeFramebuffers();
}
void SwapChain::Initialize()
{
SwapChainSupportDetails swapChainSupport{instance.GetSurface(), instance.GetPhysicalDevice()};
VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
extent = SelectSwapExtent(instance.GetWindow(), swapChainSupport.capabilities);
imageFormat = format.format;
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
if (swapChainSupport.capabilities.maxImageCount != 0)
{
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
}
QueueFamiliesQuery queueFamilies{instance.GetSurface(), instance.GetPhysicalDevice()};
std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = instance.GetSurface();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = format.format;
createInfo.imageColorSpace = format.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
CP_VK_ASSERT(vkCreateSwapchainKHR(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize the swapchain");
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, nullptr);
images.resize(imageCount);
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, images.data());
}
void SwapChain::InitializeImageViews()
{
imageViews.resize(images.size());
for (size_t i = 0; i < images.size(); i++)
{
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
void SwapChain::InitializeDepthBuffer()
{
depthImage = std::make_unique<Texture2D>(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth);
}
void SwapChain::InitializeRenderPass()
{
VkAttachmentDescription colorAttachment{};
colorAttachment.format = imageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = Image::SelectDepthFormat(instance);
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 | 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.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 = attachments.size();
renderPassCreateInfo.pAttachments = attachments.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpass;
renderPassCreateInfo.dependencyCount = 1;
renderPassCreateInfo.pDependencies = &dependency;
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
}
void SwapChain::InitializeFramebuffers()
{
framebuffers.resize(images.size());
for (size_t i = 0; i < imageViews.size(); ++i)
{
std::vector<VkImageView> attachments{imageViews[i], depthImage->GetImageView()};
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;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer");
}
}
void SwapChain::Destroy()
{
for (auto&& framebuffer : framebuffers)
{
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
}
for (auto&& swapChainImageView : imageViews)
{
vkDestroyImageView(instance.GetDevice(), swapChainImageView, nullptr);
}
vkDestroySwapchainKHR(instance.GetDevice(), handle, nullptr);
}
VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
{
for (auto&& availableFormat : availableFormats)
{
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
while (width == 0 || height == 0)
{
return availableFormat;
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
glfwWaitEvents();
}
}
return availableFormats[0];
}
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
{
return VK_PRESENT_MODE_FIFO_KHR;
for (auto&& availablePresentMode : availablePresentModes)
vkDeviceWaitIdle(instance.GetDevice());
Destroy();
Initialize();
InitializeImageViews();
InitializeDepthBuffer();
InitializeFramebuffers();
}
void SwapChain::Initialize()
{
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
SwapChainSupportDetails swapChainSupport{instance.GetSurface(), instance.GetPhysicalDevice()};
VkSurfaceFormatKHR format = SelectSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = SelectSwapPresentMode(swapChainSupport.presentModes);
extent = SelectSwapExtent(instance.GetWindow(), swapChainSupport.capabilities);
imageFormat = format.format;
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
if (swapChainSupport.capabilities.maxImageCount != 0)
{
return availablePresentMode;
imageCount = std::min(imageCount, swapChainSupport.capabilities.maxImageCount);
}
QueueFamiliesQuery queueFamilies{instance.GetSurface(), instance.GetPhysicalDevice()};
std::vector<uint32_t> queueFamilyIndices{queueFamilies.graphicsFamily.value(), queueFamilies.presentFamily.value()};
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = instance.GetSurface();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = format.format;
createInfo.imageColorSpace = format.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (queueFamilies.graphicsFamily != queueFamilies.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices.data();
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
CP_VK_ASSERT(vkCreateSwapchainKHR(instance.GetDevice(), &createInfo, nullptr, &handle), "Failed to initialize the swapchain");
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, nullptr);
images.resize(imageCount);
vkGetSwapchainImagesKHR(instance.GetDevice(), handle, &imageCount, images.data());
}
void SwapChain::InitializeImageViews()
{
imageViews.resize(images.size());
for (size_t i = 0; i < images.size(); i++)
{
imageViews[i] = Image::InitializeImageView(instance, images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
// VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D SwapChain::SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return capabilities.currentExtent;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
VkExtent2D extent{width, height};
extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return extent;
void SwapChain::InitializeDepthBuffer()
{
depthImage = std::make_unique<Texture2D>(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth);
}
void SwapChain::InitializeRenderPass()
{
VkAttachmentDescription colorAttachment{};
colorAttachment.format = imageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = Image::SelectDepthFormat(instance);
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 | 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.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 = attachments.size();
renderPassCreateInfo.pAttachments = attachments.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpass;
renderPassCreateInfo.dependencyCount = 1;
renderPassCreateInfo.pDependencies = &dependency;
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "Failed to initialze render pass");
}
void SwapChain::InitializeFramebuffers()
{
framebuffers.resize(images.size());
for (size_t i = 0; i < imageViews.size(); ++i)
{
std::vector<VkImageView> attachments{imageViews[i], depthImage->GetImageView()};
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;
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "Failed to initialize swap chain framebuffer");
}
}
void SwapChain::Destroy()
{
for (auto&& framebuffer : framebuffers)
{
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
}
for (auto&& swapChainImageView : imageViews)
{
vkDestroyImageView(instance.GetDevice(), swapChainImageView, nullptr);
}
vkDestroySwapchainKHR(instance.GetDevice(), handle, nullptr);
}
VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
{
for (auto&& availableFormat : availableFormats)
{
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
{
return availableFormat;
}
}
return availableFormats[0];
}
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
{
return VK_PRESENT_MODE_FIFO_KHR;
for (auto&& availablePresentMode : availablePresentModes)
{
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
{
return availablePresentMode;
}
}
// VK_PRESENT_MODE_FIFO_KHR is guaranteed to be present
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D SwapChain::SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return capabilities.currentExtent;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
VkExtent2D extent{width, height};
extent.width = std::clamp(extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
extent.height = std::clamp(extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return extent;
}
}
+51 -48
View File
@@ -6,60 +6,63 @@
#include <vector>
#include <GLFW/glfw3.h>
class Instance;
class CommandBuffer;
class Texture2D;
struct SwapChainSupportDetails
namespace Copium
{
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
class Instance;
class CommandBuffer;
class Texture2D;
SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice);
bool Valid();
};
struct SwapChainSupportDetails
{
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
class SwapChain final
{
CP_DELETE_COPY_AND_MOVE_CTOR(SwapChain);
private:
Instance& instance;
SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice);
bool Valid();
};
VkSwapchainKHR handle;
VkRenderPass renderPass;
VkFormat imageFormat;
VkExtent2D extent;
std::unique_ptr<Texture2D> depthImage;
std::vector<VkImageView> imageViews;
std::vector<VkImage> images;
std::vector<VkFramebuffer> framebuffers;
uint32_t imageIndex;
class SwapChain final
{
CP_DELETE_COPY_AND_MOVE_CTOR(SwapChain);
private:
Instance& instance;
public:
SwapChain(Instance& instance);
~SwapChain();
VkSwapchainKHR handle;
VkRenderPass renderPass;
VkFormat imageFormat;
VkExtent2D extent;
std::unique_ptr<Texture2D> depthImage;
std::vector<VkImageView> imageViews;
std::vector<VkImage> images;
std::vector<VkFramebuffer> framebuffers;
uint32_t imageIndex;
void BeginFrameBuffer(const CommandBuffer& commandBuffer) const;
void EndFrameBuffer(const CommandBuffer& commandBuffer) const;
VkSwapchainKHR GetHandle() const;
VkRenderPass GetRenderPass() const;
VkExtent2D GetExtent() const;
VkFramebuffer GetFramebuffer() const;
bool BeginPresent(VkSemaphore signalSemaphore);
void EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized);
void Recreate();
public:
SwapChain(Instance& instance);
~SwapChain();
void BeginFrameBuffer(const CommandBuffer& commandBuffer) const;
void EndFrameBuffer(const CommandBuffer& commandBuffer) const;
VkSwapchainKHR GetHandle() const;
VkRenderPass GetRenderPass() const;
VkExtent2D GetExtent() const;
VkFramebuffer GetFramebuffer() const;
bool BeginPresent(VkSemaphore signalSemaphore);
void EndPresent(VkQueue presentQueue, VkSemaphore* waitSemaphore, bool framebufferResized);
void Recreate();
private:
void Initialize();
void InitializeImageViews();
void InitializeDepthBuffer();
void InitializeRenderPass();
void InitializeFramebuffers();
void Destroy();
private:
void Initialize();
void InitializeImageViews();
void InitializeDepthBuffer();
void InitializeRenderPass();
void InitializeFramebuffers();
void Destroy();
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
};
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
};
}
+140 -137
View File
@@ -3,148 +3,151 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
Texture2D::Texture2D(Instance& instance, const std::string& filename)
: instance{instance}, type{Type::Static}, format{Format::Image}
namespace Copium
{
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()
{
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);
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
}
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const
{
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler;
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;
}
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)
{
int texWidth;
int texHeight;
int texChannels;
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
CP_ASSERT(pixels, "InitializeTextureImage : 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);
images.resize(1);
imageMemories.resize(1);
imageViews.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, &images.front(), &imageMemories.front());
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
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++)
Texture2D::Texture2D(Instance& instance, const std::string& filename)
: instance{instance}, type{Type::Static}, format{Format::Image}
{
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);
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()
{
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);
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
}
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const
{
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = sampler;
switch (type) {
case Type::Static:
imageInfo.imageView = imageViews.front();
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);
case Type::Dynamic:
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for dynamic texture");
imageInfo.imageView = imageViews[index];
break;
}
case Format::Image:
{
CP_ABORT("InitializeTexture : Image format currently not supported");
}
default:
CP_ABORT("InitializeTexture : Unreachable switch case");
CP_ABORT("GetDescriptorImageInfo : Unreachable switch case");
}
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)
{
int texWidth;
int texHeight;
int texChannels;
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
CP_ASSERT(pixels, "InitializeTextureImage : 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);
images.resize(1);
imageMemories.resize(1);
imageViews.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, &images.front(), &imageMemories.front());
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
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");
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");
}
}
+36 -34
View File
@@ -6,40 +6,42 @@
#include "Image.h"
#include "Instance.h"
// TODO: Separate Texture2D and Framebuffer Attachments
class Texture2D
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
public:
enum class Type
// TODO: Separate Texture2D and Framebuffer Attachments
class Texture2D
{
Static, Dynamic
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
public:
enum class Type
{
Static, Dynamic
};
enum class Format
{
Image, Color, Depth
};
private:
Instance& instance;
std::vector<VkImage> images;
std::vector<VkDeviceMemory> imageMemories;
std::vector<VkImageView> imageViews;
VkSampler sampler;
Type type;
Format format;
public:
Texture2D(Instance& instance, const std::string& filename);
Texture2D(Instance& instance, int width, int height, Type type, Format format);
~Texture2D();
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const;
VkImageView GetImageView() const;
VkImageView GetImageView(int index);
private:
void InitializeTextureImage(const std::string& filename);
void InitializeTexture(int width, int height);
void InitializeSampler();
};
enum class Format
{
Image, Color, Depth
};
private:
Instance& instance;
std::vector<VkImage> images;
std::vector<VkDeviceMemory> imageMemories;
std::vector<VkImageView> imageViews;
VkSampler sampler;
Type type;
Format format;
public:
Texture2D(Instance& instance, const std::string& filename);
Texture2D(Instance& instance, int width, int height, Type type, Format format);
~Texture2D();
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const;
VkImageView GetImageView() const;
VkImageView GetImageView(int index);
private:
void InitializeTextureImage(const std::string& filename);
void InitializeTexture(int width, int height);
void InitializeSampler();
};
}
+19 -16
View File
@@ -2,22 +2,25 @@
#include <chrono>
class Timer
namespace Copium
{
private:
std::chrono::time_point<std::chrono::steady_clock> startTime;
public:
Timer()
: startTime{std::chrono::steady_clock::now()}
{}
class Timer
{
private:
std::chrono::time_point<std::chrono::steady_clock> startTime;
public:
Timer()
: startTime{std::chrono::steady_clock::now()}
{}
void Start()
{
startTime = std::chrono::steady_clock::now();
}
void Start()
{
startTime = std::chrono::steady_clock::now();
}
double Elapsed()
{
return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
}
};
double Elapsed()
{
return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
}
};
}
+25 -22
View File
@@ -4,28 +4,31 @@
#include "Buffer.h"
#include <vulkan/vulkan.hpp>
class UniformBuffer : public Buffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
public:
UniformBuffer(Instance& instance, VkDeviceSize size)
: Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, instance.GetMaxFramesInFlight()}
{}
template <typename T>
void Update(const T& t)
class UniformBuffer : public Buffer
{
CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize());
Buffer::Update((void*)&t, instance.GetFlightIndex());
}
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
{
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = handle;
bufferInfo.offset = (VkDeviceSize)index * size;
bufferInfo.range = size;
return bufferInfo;
}
};
public:
UniformBuffer(Instance& instance, VkDeviceSize size)
: Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, instance.GetMaxFramesInFlight()}
{}
template <typename 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());
Buffer::Update((void*)&t, instance.GetFlightIndex());
}
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
{
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = handle;
bufferInfo.offset = (VkDeviceSize)index * size;
bufferInfo.range = size;
return bufferInfo;
}
};
}
+16 -13
View File
@@ -4,18 +4,21 @@
#include <vulkan/vulkan.hpp>
#include "VertexDescriptor.h"
struct Vertex {
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;
namespace Copium
{
struct Vertex {
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
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;
}
};
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
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;
}
};
}
+27 -24
View File
@@ -3,33 +3,36 @@
#include "Buffer.h"
#include "VertexDescriptor.h"
class VertexBuffer : public Buffer
namespace Copium
{
CP_DELETE_COPY_AND_MOVE_CTOR(VertexBuffer);
private:
std::vector<VkDeviceSize> bindingOffsets;
std::vector<VkDeviceSize> bindingSizes;
public:
VertexBuffer(Instance& instance, const VertexDescriptor& descriptor, int vertexCount)
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, descriptor.GetVertexSize() * vertexCount, 1}
class VertexBuffer : public Buffer
{
VkDeviceSize offset = 0;
for (auto&& binding : descriptor.GetBindings())
CP_DELETE_COPY_AND_MOVE_CTOR(VertexBuffer);
private:
std::vector<VkDeviceSize> bindingOffsets;
std::vector<VkDeviceSize> bindingSizes;
public:
VertexBuffer(Instance& instance, const VertexDescriptor& descriptor, int vertexCount)
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, descriptor.GetVertexSize() * vertexCount, 1}
{
bindingOffsets.emplace_back(offset);
bindingSizes.emplace_back(binding.stride * vertexCount);
offset += binding.stride * vertexCount;
VkDeviceSize offset = 0;
for (auto&& binding : descriptor.GetBindings())
{
bindingOffsets.emplace_back(offset);
bindingSizes.emplace_back(binding.stride * vertexCount);
offset += binding.stride * vertexCount;
}
}
}
void Bind(const CommandBuffer& commandBuffer) override
{
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
}
void Bind(const CommandBuffer& commandBuffer) override
{
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
}
void Update(uint32_t binding, void* data)
{
UpdateStaging(data, bindingOffsets[binding], bindingSizes[binding]);
}
};
void Update(uint32_t binding, void* data)
{
UpdateStaging(data, bindingOffsets[binding], bindingSizes[binding]);
}
};
}
+50 -48
View File
@@ -2,59 +2,61 @@
#include <map>
#include <vulkan/vulkan.hpp>
class VertexDescriptor
namespace Copium
{
private:
uint32_t bindingIndex = 0;
std::vector<VkVertexInputBindingDescription> bindings;
std::vector<VkVertexInputAttributeDescription> attributes;
public:
template <typename T>
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset)
class VertexDescriptor
{
CP_ASSERT(binding <= bindings.size(), "Attribute binding must less than or be equal to the amount of current bindings");
private:
uint32_t bindingIndex = 0;
std::vector<VkVertexInputBindingDescription> bindings;
std::vector<VkVertexInputAttributeDescription> attributes;
if (binding == bindings.size())
AddLayout(binding, sizeof(T));
VkVertexInputAttributeDescription description{};
description.binding = binding;
description.location = location;
description.format = format;
description.offset = offset;
attributes.emplace_back(description);
}
VkDeviceSize GetVertexSize() const
{
VkDeviceSize bufferSize = 0;
for (auto&& binding : bindings)
public:
template <typename T>
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset)
{
bufferSize += binding.stride;
CP_ASSERT(binding <= bindings.size(), "Attribute binding must less than or be equal to the amount of current bindings");
if (binding == bindings.size())
AddLayout(binding, sizeof(T));
VkVertexInputAttributeDescription description{};
description.binding = binding;
description.location = location;
description.format = format;
description.offset = offset;
attributes.emplace_back(description);
}
return bufferSize;
}
const std::vector<VkVertexInputAttributeDescription>& GetAttributes() const
{
return attributes;
}
VkDeviceSize GetVertexSize() const
{
VkDeviceSize bufferSize = 0;
for (auto&& binding : bindings)
{
bufferSize += binding.stride;
}
return bufferSize;
}
const std::vector<VkVertexInputBindingDescription>& GetBindings() const
{
return bindings;
}
const std::vector<VkVertexInputAttributeDescription>& GetAttributes() const
{
return attributes;
}
private:
uint32_t AddLayout(uint32_t binding, uint32_t size)
{
VkVertexInputBindingDescription description{};
description.binding = binding;
description.stride = size;
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
bindings.emplace_back(description);
return description.binding;
}
};
const std::vector<VkVertexInputBindingDescription>& GetBindings() const
{
return bindings;
}
private:
uint32_t AddLayout(uint32_t binding, uint32_t size)
{
VkVertexInputBindingDescription description{};
description.binding = binding;
description.stride = size;
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
bindings.emplace_back(description);
return description.binding;
}
};
}
+12 -9
View File
@@ -4,13 +4,16 @@
#include <vulkan/vulkan.hpp>
#include "VertexDescriptor.h"
struct VertexPassthrough {
glm::vec2 texCoord;
namespace Copium
{
struct VertexPassthrough {
glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
descriptor.AddAttribute<VertexPassthrough>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough , texCoord));
return descriptor;
}
};
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
descriptor.AddAttribute<VertexPassthrough>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough, texCoord));
return descriptor;
}
};
}
+9 -6
View File
@@ -2,10 +2,13 @@
#include <stdexcept>
class VulkanException : public std::runtime_error
namespace Copium
{
public:
VulkanException(const std::string& str)
: runtime_error{str.c_str()}
{}
};
class VulkanException : public std::runtime_error
{
public:
VulkanException(const std::string& str)
: runtime_error{str.c_str()}
{}
};
}
-6
View File
@@ -1,6 +0,0 @@
#pragma once
class Window
{
};
+4 -239
View File
@@ -1,250 +1,15 @@
#include "Buffer.h"
#include "DescriptorPool.h"
#include "DescriptorSet.h"
#include "Framebuffer.h"
#include "IndexBuffer.h"
#include "Instance.h"
#include "Pipeline.h"
#include "Texture2D.h"
#include "Application.h"
#include "Common.h"
#include "Timer.h"
#include "UniformBuffer.h"
#include "Vertex.h"
#include "VertexBuffer.h"
#include "VertexPassthrough.h"
#include <GLFW/glfw3.h>
#include <chrono>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <optional>
#include <set>
#include <vector>
const std::vector<Vertex> vertices = {
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,
4, 5, 6, 6, 7, 4
};
const std::vector<VertexPassthrough> verticesPassthrough = {
VertexPassthrough{{-1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, -1.0f}},
VertexPassthrough{{ 1.0f, 1.0f}},
VertexPassthrough{{-1.0f, 1.0f}},
};
const std::vector<uint16_t> indicesPassthrough = {
0, 1, 2, 2, 3, 0,
};
struct alignas(64) ShaderUniform
{
alignas(16) glm::mat4 projection;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 model;
alignas(16) glm::vec3 lightPos;
};
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<CommandBuffer> commandBuffer;
std::unique_ptr<Framebuffer> framebuffer;
std::unique_ptr<Pipeline> graphicsPipelinePassthrough;
std::unique_ptr<VertexBuffer> vertexBufferPassthrough;
std::unique_ptr<IndexBuffer> indexBufferPassthrough;
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
public:
Application()
{
InitializeInstance();
InitializeFrameBuffer();
InitializeGraphicsPipeline();
InitializeTextureSampler();
InitializeUniformBuffer();
InitializeDescriptorSets();
InitializeVertexBuffer();
InitializeIndexBuffer();
InitializeCommandBuffer();
}
~Application()
{
vkDeviceWaitIdle(instance->GetDevice());
}
Application(Application&&) = delete;
Application(const Application&) = delete;
Application& operator=(Application&&) = delete;
Application& operator=(const Application&) = delete;
bool Update()
{
if (!instance->BeginPresent())
return true;
RecordCommandBuffer();
commandBuffer->SubmitAsGraphicsQueue();
return instance->EndPresent();
}
private:
void InitializeInstance()
{
instance = std::make_unique<Instance>("Copium Engine");
}
void InitializeFrameBuffer()
{
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
}
void InitializeTextureSampler()
{
texture2D = std::make_unique<Texture2D>(*instance, "res/textures/texture.png");
}
void InitializeUniformBuffer()
{
shaderUniformBuffer = std::make_unique<UniformBuffer>(*instance, sizeof(ShaderUniform));
}
void InitializeDescriptorSets()
{
descriptorPool = std::make_unique<DescriptorPool>(*instance);
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
descriptorSet->AddTexture2D(*texture2D, 1);
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0);
}
void InitializeGraphicsPipeline()
{
PipelineCreator creator{framebuffer->GetRenderPass(), "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);
PipelineCreator creatorPassthrough{instance->GetSwapChain().GetRenderPass(), "res/shaders/passthrough.vert", "res/shaders/passthrough.frag"};
creatorPassthrough.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
creatorPassthrough.SetVertexDescriptor(VertexPassthrough::GetDescriptor());
creatorPassthrough.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipelinePassthrough = std::make_unique<Pipeline>(*instance, creatorPassthrough);
}
void InitializeVertexBuffer()
{
vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size());
vertexBuffer->Update(0, (void*)vertices.data());
vertexBufferPassthrough = std::make_unique<VertexBuffer>(*instance, VertexPassthrough::GetDescriptor(), verticesPassthrough.size());
vertexBufferPassthrough->Update(0, (void*)verticesPassthrough.data());
}
void InitializeIndexBuffer()
{
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
indexBuffer->UpdateStaging((void*)indices.data());
indexBufferPassthrough = std::make_unique<IndexBuffer>(*instance, indicesPassthrough.size());
indexBufferPassthrough->UpdateStaging((void*)indicesPassthrough.data());
}
void InitializeCommandBuffer()
{
commandBuffer = std::make_unique<CommandBuffer>(*instance, CommandBufferType::Dynamic);
}
void RecordCommandBuffer()
{
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);
graphicsPipeline->Bind(*commandBuffer);
UpdateUniformBuffer();
vertexBuffer->Bind(*commandBuffer);
indexBuffer->Bind(*commandBuffer);
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
indexBuffer->Draw(*commandBuffer);
framebuffer->Unbind(*commandBuffer);
instance->GetSwapChain().BeginFrameBuffer(*commandBuffer);
graphicsPipelinePassthrough->Bind(*commandBuffer);
graphicsPipelinePassthrough->SetDescriptorSet(0, *descriptorSetPassthrough);
graphicsPipelinePassthrough->BindDescriptorSets(commandBuffer->GetHandle());
vertexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Bind(*commandBuffer);
indexBufferPassthrough->Draw(*commandBuffer);
instance->GetSwapChain().EndFrameBuffer(*commandBuffer);
commandBuffer->End();
}
void UpdateUniformBuffer()
{
static Timer startTimer;
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.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);
}
};
void func(const int* ptr) {
*const_cast<int*>(ptr) = 20;
}
int main()
{
CP_ASSERT(glfwInit() == GLFW_TRUE, "main : Failed to initialize the glfw context");
{
Application application;
Timer timer;
Copium::Application application;
Copium::Timer timer;
int frames = 0;
while (application.Update())
{