Add file structure to code
- Rename project to CopiumEngine
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
#include "copium/core/Application.h"
|
||||
|
||||
#include "copium/mesh/Vertex.h"
|
||||
#include "copium/mesh/VertexPassthrough.h"
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
Application::Application()
|
||||
{
|
||||
InitializeInstance();
|
||||
InitializeFrameBuffer();
|
||||
InitializeGraphicsPipeline();
|
||||
InitializeTextureSampler();
|
||||
InitializeUniformBuffer();
|
||||
InitializeDescriptorSets();
|
||||
InitializeVertexBuffer();
|
||||
InitializeIndexBuffer();
|
||||
InitializeCommandBuffer();
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
vkDeviceWaitIdle(instance->GetDevice());
|
||||
}
|
||||
|
||||
bool Application::Update()
|
||||
{
|
||||
if (framebuffer->GetWidth() != instance->GetSwapChain().GetExtent().width || framebuffer->GetHeight() != instance->GetSwapChain().GetExtent().height)
|
||||
{
|
||||
framebuffer->Resize(instance->GetSwapChain().GetExtent().width / 8, instance->GetSwapChain().GetExtent().height / 8);
|
||||
descriptorSetPassthrough->AddSampler(framebuffer->GetColorAttachment(), 0);
|
||||
}
|
||||
if (!instance->BeginPresent())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RecordCommandBuffer();
|
||||
commandBuffer->SubmitAsGraphicsQueue();
|
||||
|
||||
return instance->EndPresent();
|
||||
}
|
||||
|
||||
void Application::InitializeInstance()
|
||||
{
|
||||
instance = std::make_unique<Instance>("Copium Engine");
|
||||
}
|
||||
|
||||
void Application::InitializeFrameBuffer()
|
||||
{
|
||||
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
|
||||
}
|
||||
|
||||
void Application::InitializeTextureSampler()
|
||||
{
|
||||
texture2D = std::make_unique<Texture2D>(*instance, "res/textures/texture.png");
|
||||
}
|
||||
|
||||
void Application::InitializeUniformBuffer()
|
||||
{
|
||||
shaderUniformBuffer = std::make_unique<UniformBuffer>(*instance, sizeof(ShaderUniform));
|
||||
}
|
||||
|
||||
void Application::InitializeDescriptorSets()
|
||||
{
|
||||
descriptorPool = std::make_unique<DescriptorPool>(*instance);
|
||||
|
||||
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
|
||||
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
|
||||
descriptorSet->AddSampler(*texture2D, 1);
|
||||
|
||||
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
|
||||
descriptorSetPassthrough->AddSampler(framebuffer->GetColorAttachment(), 0);
|
||||
}
|
||||
|
||||
void Application::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 Application::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 Application::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 Application::InitializeCommandBuffer()
|
||||
{
|
||||
commandBuffer = std::make_unique<CommandBuffer>(*instance, CommandBuffer::Type::Dynamic);
|
||||
}
|
||||
|
||||
void Application::RecordCommandBuffer()
|
||||
{
|
||||
commandBuffer->Begin();
|
||||
|
||||
framebuffer->Bind(*commandBuffer);
|
||||
graphicsPipeline->Bind(*commandBuffer);
|
||||
|
||||
UpdateUniformBuffer();
|
||||
|
||||
vertexBuffer->Bind(*commandBuffer);
|
||||
indexBuffer->Bind(*commandBuffer);
|
||||
|
||||
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
|
||||
graphicsPipeline->BindDescriptorSets(*commandBuffer);
|
||||
|
||||
indexBuffer->Draw(*commandBuffer);
|
||||
framebuffer->Unbind(*commandBuffer);
|
||||
|
||||
instance->GetSwapChain().BeginFrameBuffer(*commandBuffer);
|
||||
|
||||
graphicsPipelinePassthrough->Bind(*commandBuffer);
|
||||
graphicsPipelinePassthrough->SetDescriptorSet(0, *descriptorSetPassthrough);
|
||||
graphicsPipelinePassthrough->BindDescriptorSets(*commandBuffer);
|
||||
vertexBufferPassthrough->Bind(*commandBuffer);
|
||||
indexBufferPassthrough->Bind(*commandBuffer);
|
||||
indexBufferPassthrough->Draw(*commandBuffer);
|
||||
|
||||
instance->GetSwapChain().EndFrameBuffer(*commandBuffer);
|
||||
commandBuffer->End();
|
||||
}
|
||||
|
||||
void Application::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), framebuffer->GetWidth() / (float)framebuffer->GetHeight(), 0.1f, 10.0f);
|
||||
shaderUniform.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
shaderUniform.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/buffer/Framebuffer.h"
|
||||
#include "copium/buffer/IndexBuffer.h"
|
||||
#include "copium/buffer/UniformBuffer.h"
|
||||
#include "copium/buffer/VertexBuffer.h"
|
||||
#include "copium/core/Instance.h"
|
||||
#include "copium/pipeline/DescriptorPool.h"
|
||||
#include "copium/pipeline/DescriptorSet.h"
|
||||
#include "copium/pipeline/Pipeline.h"
|
||||
#include "copium/sampler/Texture2D.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Application final
|
||||
{
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(Application);
|
||||
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();
|
||||
~Application();
|
||||
|
||||
bool Update();
|
||||
private:
|
||||
void InitializeInstance();
|
||||
void InitializeFrameBuffer();
|
||||
void InitializeTextureSampler();
|
||||
void InitializeUniformBuffer();
|
||||
void InitializeDescriptorSets();
|
||||
void InitializeGraphicsPipeline();
|
||||
void InitializeVertexBuffer();
|
||||
void InitializeIndexBuffer();
|
||||
void InitializeCommandBuffer();
|
||||
void RecordCommandBuffer();
|
||||
void UpdateUniformBuffer();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "copium/core/DebugMessenger.h"
|
||||
|
||||
#include "copium/core/Instance.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
DebugMessenger::DebugMessenger(Instance& instance)
|
||||
: instance{instance}
|
||||
{
|
||||
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), "DebugMessenger : Failed to initialze debug messenger");
|
||||
}
|
||||
|
||||
DebugMessenger::~DebugMessenger()
|
||||
{
|
||||
vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
|
||||
}
|
||||
|
||||
void DebugMessenger::AddRequiredExtensions(std::vector<const char*>* extensions)
|
||||
{
|
||||
extensions->emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
void DebugMessenger::AddRequiredLayers(std::vector<const char*>* layers)
|
||||
{
|
||||
layers->emplace_back("VK_LAYER_KHRONOS_validation");
|
||||
}
|
||||
#else
|
||||
DebugMessenger::DebugMessenger(VkInstance instance)
|
||||
: instance{instance}
|
||||
{}
|
||||
|
||||
DebugMessenger::~DebugMessenger()
|
||||
{}
|
||||
|
||||
void DebugMessenger::AddRequiredExtensions(std::vector<const char*>* extensions)
|
||||
{}
|
||||
|
||||
void DebugMessenger::AddRequiredLayers(std::vector<const char*>* layers)
|
||||
{}
|
||||
#endif
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessenger::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData)
|
||||
{
|
||||
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||
{
|
||||
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||
CP_ABORT("DebugCallback : %s", pCallbackData->pMessage);
|
||||
else
|
||||
CP_WARN("DebugCallback : %s", pCallbackData->pMessage);
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult DebugMessenger::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;
|
||||
}
|
||||
|
||||
void DebugMessenger::vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||
VkDebugUtilsMessengerEXT debugMessenger,
|
||||
const VkAllocationCallbacks* pAllocator) {
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||
if (func != nullptr) {
|
||||
func(instance, debugMessenger, pAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/util/Common.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Instance;
|
||||
|
||||
class DebugMessenger final
|
||||
{
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
|
||||
private:
|
||||
Instance& instance;
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
public:
|
||||
DebugMessenger(Instance& instance);
|
||||
~DebugMessenger();
|
||||
|
||||
static void AddRequiredExtensions(std::vector<const char*>* extensions);
|
||||
static void AddRequiredLayers(std::vector<const char*>* layers);
|
||||
|
||||
private:
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData);
|
||||
|
||||
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkDebugUtilsMessengerEXT* pDebugMessenger);
|
||||
|
||||
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||
VkDebugUtilsMessengerEXT debugMessenger,
|
||||
const VkAllocationCallbacks* pAllocator);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
#include "Instance.h"
|
||||
|
||||
#include "copium/core/QueueFamilies.h"
|
||||
#include "copium/util/Common.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
Instance::Instance(const std::string& applicationName)
|
||||
{
|
||||
timer.Start();
|
||||
InitializeWindow(applicationName);
|
||||
InitializeInstance(applicationName);
|
||||
InitializeDebugMessenger();
|
||||
InitializeSurface();
|
||||
SelectPhysicalDevice();
|
||||
InitializeLogicalDevice();
|
||||
InitializeCommandPool();
|
||||
InitializeSwapChain();
|
||||
InitializeSyncObjects();
|
||||
CP_INFO("Instance : Initialized Vulkan in %f seconds", timer.Elapsed());
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
{
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||
{
|
||||
vkDestroyFence(device, inFlightFences[i], nullptr);
|
||||
vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
|
||||
vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
|
||||
}
|
||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||
swapChain.reset();
|
||||
vkDestroyDevice(device, nullptr);
|
||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||
debugMessenger.reset();
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
glfwDestroyWindow(window);
|
||||
}
|
||||
|
||||
bool Instance::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 Instance::EndPresent()
|
||||
{
|
||||
swapChain->EndPresent(presentQueue, &renderFinishedSemaphores[flightIndex], framebufferResized);
|
||||
|
||||
framebufferResized = false;
|
||||
flightIndex = (flightIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
return !glfwWindowShouldClose(window);
|
||||
}
|
||||
|
||||
void Instance::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]), "SubmitGraphicsQueue : Failed to submit command buffer");
|
||||
}
|
||||
|
||||
GLFWwindow* Instance::GetWindow() const
|
||||
{
|
||||
return window;
|
||||
}
|
||||
|
||||
VkSurfaceKHR Instance::GetSurface() const
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
|
||||
VkPhysicalDevice Instance::GetPhysicalDevice() const
|
||||
{
|
||||
return physicalDevice;
|
||||
}
|
||||
|
||||
VkDevice Instance::GetDevice() const
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
VkCommandPool Instance::GetCommandPool() const
|
||||
{
|
||||
return commandPool;
|
||||
}
|
||||
|
||||
VkQueue Instance::GetGraphicsQueue() const
|
||||
{
|
||||
return graphicsQueue;
|
||||
}
|
||||
|
||||
int Instance::GetFlightIndex() const
|
||||
{
|
||||
return flightIndex;
|
||||
}
|
||||
|
||||
int Instance::GetMaxFramesInFlight() const
|
||||
{
|
||||
return MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
const SwapChain& Instance::GetSwapChain() const
|
||||
{
|
||||
return *swapChain;
|
||||
}
|
||||
|
||||
uint32_t Instance::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;
|
||||
}
|
||||
CP_ABORT("FindMemoryType : Failed to find suitable memory type");
|
||||
}
|
||||
|
||||
Instance::operator VkInstance() const
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Instance::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);
|
||||
#elif defined(BORDERLESS_WINDOWED)
|
||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
window = glfwCreateWindow(mode->width, mode->height, applicationName.c_str(), nullptr, nullptr);
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||
#else
|
||||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, applicationName.c_str(), nullptr, nullptr);
|
||||
#endif
|
||||
CP_ASSERT(window, "InitializeWindow : Failed to initialize glfw window");
|
||||
|
||||
glfwSetWindowUserPointer(window, this);
|
||||
glfwSetFramebufferSizeCallback(window, FramebufferResizeCallback);
|
||||
}
|
||||
|
||||
void Instance::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("InitiaizeInstace : 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), "InitializeInstance : 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), "InitializeInstance : Failed to create instance");
|
||||
}
|
||||
|
||||
void Instance::InitializeDebugMessenger()
|
||||
{
|
||||
debugMessenger = std::make_unique<DebugMessenger>(*this);
|
||||
}
|
||||
|
||||
void Instance::InitializeSurface()
|
||||
{
|
||||
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "InitializeSurface : Failed to create Vulkan surface");
|
||||
}
|
||||
|
||||
void Instance::SelectPhysicalDevice()
|
||||
{
|
||||
uint32_t deviceCount;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
CP_ASSERT(deviceCount != 0, "SelectPhysicaDevice : No available devices support Vulkan");
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
CP_INFO("SelectPhysicaDevice : Available devices:");
|
||||
for (auto&& device : devices)
|
||||
{
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
CP_INFO_CONT("\t%s", deviceProperties.deviceName);
|
||||
}
|
||||
for (auto&& device : devices)
|
||||
{
|
||||
if (IsPhysicalDeviceSuitable(device))
|
||||
{
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
physicalDevice = device;
|
||||
CP_INFO("SelectPhysicaDevice : Selecting device: %s", deviceProperties.deviceName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CP_ASSERT(physicalDevice != VK_NULL_HANDLE, "SelectPhysicaDevice : Failed to find suitable GPU");
|
||||
}
|
||||
|
||||
void Instance::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), "InitializeLogicalDevice : Failed to initialize logical device");
|
||||
|
||||
graphicsQueueIndex = query.graphicsFamily.value();
|
||||
presentQueueIndex = query.presentFamily.value();
|
||||
vkGetDeviceQueue(device, graphicsQueueIndex, 0, &graphicsQueue);
|
||||
vkGetDeviceQueue(device, presentQueueIndex, 0, &presentQueue);
|
||||
}
|
||||
|
||||
void Instance::InitializeSwapChain()
|
||||
{
|
||||
swapChain = std::make_unique<SwapChain>(*this);
|
||||
}
|
||||
|
||||
void Instance::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), "InitializeCommandPool : Failed to initialize command pool");
|
||||
}
|
||||
|
||||
void Instance::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]), "InitializeSyncObjects : Failed to initialize available image semaphore");
|
||||
CP_VK_ASSERT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderFinishedSemaphores[i]), "InitializeSyncObjects : 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]), "InitializeSyncObjects : Failed to initialize in flight fence");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const char*> Instance::GetRequiredExtensions()
|
||||
{
|
||||
uint32_t glfwExtensionCount;
|
||||
const char** glfwExtensions;
|
||||
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||
|
||||
std::vector<const char*> extensions{glfwExtensions, glfwExtensions + glfwExtensionCount};
|
||||
|
||||
debugMessenger->AddRequiredExtensions(&extensions);
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
bool Instance::CheckLayerSupport(const std::vector<const char*>& layers)
|
||||
{
|
||||
uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
|
||||
CP_INFO("CheckLayerSupport : Supported Layers:");
|
||||
for (auto&& availableLayer : availableLayers)
|
||||
{
|
||||
CP_INFO_CONT("\t%s", availableLayer.layerName);
|
||||
}
|
||||
|
||||
for (auto&& layer : layers)
|
||||
{
|
||||
bool layerFound = false;
|
||||
for (auto&& availableLayer : availableLayers)
|
||||
{
|
||||
if (std::strcmp(layer, availableLayer.layerName) == 0)
|
||||
{
|
||||
layerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!layerFound)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::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 Instance::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*> Instance::GetRequiredDeviceExtensions()
|
||||
{
|
||||
return {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
}
|
||||
|
||||
void Instance::FramebufferResizeCallback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
Instance* instance = static_cast<Instance*>(glfwGetWindowUserPointer(window));
|
||||
instance->framebufferResized = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/core/DebugMessenger.h"
|
||||
#include "copium/core/SwapChain.h"
|
||||
#include "copium/util/Timer.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <set>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Instance final
|
||||
{
|
||||
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);
|
||||
~Instance();
|
||||
bool BeginPresent();
|
||||
bool EndPresent();
|
||||
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers);
|
||||
GLFWwindow* GetWindow() const;
|
||||
VkSurfaceKHR GetSurface() const;
|
||||
VkPhysicalDevice GetPhysicalDevice() const;
|
||||
VkDevice GetDevice() const;
|
||||
VkCommandPool GetCommandPool() const;
|
||||
VkQueue GetGraphicsQueue() const;
|
||||
int GetFlightIndex() const;
|
||||
int GetMaxFramesInFlight() const;
|
||||
const SwapChain& GetSwapChain() const;
|
||||
// TODO: Create Device class and move this there
|
||||
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
|
||||
operator VkInstance() const;
|
||||
|
||||
private:
|
||||
void InitializeWindow(const std::string& applicationName);
|
||||
void InitializeInstance(const std::string& applicationName);
|
||||
void InitializeDebugMessenger();
|
||||
void InitializeSurface();
|
||||
void SelectPhysicalDevice();
|
||||
void InitializeLogicalDevice();
|
||||
void InitializeSwapChain();
|
||||
void InitializeCommandPool();
|
||||
void InitializeSyncObjects();
|
||||
std::vector<const char*> GetRequiredExtensions();
|
||||
bool CheckLayerSupport(const std::vector<const char*>& layers);
|
||||
bool IsPhysicalDeviceSuitable(VkPhysicalDevice device);
|
||||
bool CheckDeviceExtensionSupport(VkPhysicalDevice device);
|
||||
std::vector<const char*> GetRequiredDeviceExtensions();
|
||||
static void FramebufferResizeCallback(GLFWwindow* window, int width, int height);
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "copium/core/QueueFamilies.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
QueueFamiliesQuery::QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
graphicsFamily = i;
|
||||
}
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
||||
if (presentSupport)
|
||||
{
|
||||
presentFamily = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool QueueFamiliesQuery::AllRequiredFamiliesSupported()
|
||||
{
|
||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
struct QueueFamiliesQuery
|
||||
{
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
|
||||
QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device);
|
||||
|
||||
bool AllRequiredFamiliesSupported();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
#include "copium/core/SwapChain.h"
|
||||
|
||||
#include "copium/buffer/CommandBuffer.h"
|
||||
#include "copium/core/Instance.h"
|
||||
#include "copium/core/QueueFamilies.h"
|
||||
#include "copium/sampler/DepthAttachment.h"
|
||||
#include "copium/sampler/Image.h"
|
||||
|
||||
#include <glfw/glfw3.h>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
SwapChainSupportDetails::SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice)
|
||||
{
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
|
||||
if (formatCount != 0)
|
||||
{
|
||||
formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data());
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
|
||||
if (presentModeCount != 0)
|
||||
{
|
||||
presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
|
||||
}
|
||||
}
|
||||
|
||||
bool SwapChainSupportDetails::Valid()
|
||||
{
|
||||
return !formats.empty() && !presentModes.empty();
|
||||
}
|
||||
|
||||
SwapChain::SwapChain(Instance& instance)
|
||||
: instance{instance}
|
||||
{
|
||||
Initialize();
|
||||
InitializeImageViews();
|
||||
InitializeDepthAttachment();
|
||||
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);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = extent.width;
|
||||
viewport.height = extent.height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = extent;
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
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);
|
||||
while (width == 0 || height == 0)
|
||||
{
|
||||
glfwGetFramebufferSize(instance.GetWindow(), &width, &height);
|
||||
glfwWaitEvents();
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(instance.GetDevice());
|
||||
|
||||
Destroy();
|
||||
|
||||
Initialize();
|
||||
InitializeImageViews();
|
||||
InitializeDepthAttachment();
|
||||
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), "Initialize : 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::InitializeDepthAttachment()
|
||||
{
|
||||
depthAttachment = std::make_unique<DepthAttachment>(instance, extent.width, extent.height);
|
||||
}
|
||||
|
||||
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), "InitializeRenderPass : 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], depthAttachment->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]), "InitializeFramebuffers : 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/util/Common.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Instance;
|
||||
class CommandBuffer;
|
||||
class DepthAttachment;
|
||||
|
||||
struct SwapChainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
|
||||
SwapChainSupportDetails(VkSurfaceKHR surface, VkPhysicalDevice physicalDevice);
|
||||
bool Valid();
|
||||
};
|
||||
|
||||
class SwapChain final
|
||||
{
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(SwapChain);
|
||||
private:
|
||||
Instance& instance;
|
||||
|
||||
VkSwapchainKHR handle;
|
||||
VkRenderPass renderPass;
|
||||
VkFormat imageFormat;
|
||||
VkExtent2D extent;
|
||||
std::unique_ptr<DepthAttachment> depthAttachment;
|
||||
std::vector<VkImageView> imageViews;
|
||||
std::vector<VkImage> images;
|
||||
std::vector<VkFramebuffer> framebuffers;
|
||||
uint32_t imageIndex;
|
||||
|
||||
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 InitializeDepthAttachment();
|
||||
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);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user