Add cpp file for all classes
This commit is contained in:
@@ -163,9 +163,34 @@
|
|||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\Application.cpp" />
|
||||||
|
<ClCompile Include="src\Buffer.cpp" />
|
||||||
|
<ClCompile Include="src\ColorAttachment.cpp" />
|
||||||
|
<ClCompile Include="src\CommandBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\CommandBufferScoped.cpp" />
|
||||||
|
<ClCompile Include="src\DebugMessenger.cpp" />
|
||||||
|
<ClCompile Include="src\DepthAttachment.cpp" />
|
||||||
|
<ClCompile Include="src\DescriptorPool.cpp" />
|
||||||
|
<ClCompile Include="src\DescriptorSet.cpp" />
|
||||||
|
<ClCompile Include="src\FileSystem.cpp" />
|
||||||
|
<ClCompile Include="src\Framebuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Image.cpp" />
|
||||||
|
<ClCompile Include="src\IndexBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Instance.cpp" />
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
|
<ClCompile Include="src\Pipeline.cpp" />
|
||||||
|
<ClCompile Include="src\PipelineCreator.cpp" />
|
||||||
|
<ClCompile Include="src\QueueFamilies.cpp" />
|
||||||
|
<ClCompile Include="src\Sampler.cpp" />
|
||||||
|
<ClCompile Include="src\Shader.cpp" />
|
||||||
<ClCompile Include="src\SwapChain.cpp" />
|
<ClCompile Include="src\SwapChain.cpp" />
|
||||||
<ClCompile Include="src\Texture2D.cpp" />
|
<ClCompile Include="src\Texture2D.cpp" />
|
||||||
|
<ClCompile Include="src\Timer.cpp" />
|
||||||
|
<ClCompile Include="src\UniformBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\Vertex.cpp" />
|
||||||
|
<ClCompile Include="src\VertexBuffer.cpp" />
|
||||||
|
<ClCompile Include="src\VertexDescriptor.cpp" />
|
||||||
|
<ClCompile Include="src\VertexPassthrough.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\DepthAttachment.h" />
|
<ClInclude Include="src\DepthAttachment.h" />
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include "Vertex.h"
|
||||||
|
#include "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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-203
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Buffer.h"
|
|
||||||
#include "DescriptorPool.h"
|
#include "DescriptorPool.h"
|
||||||
#include "DescriptorSet.h"
|
#include "DescriptorSet.h"
|
||||||
#include "Framebuffer.h"
|
#include "Framebuffer.h"
|
||||||
@@ -8,58 +7,14 @@
|
|||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Pipeline.h"
|
#include "Pipeline.h"
|
||||||
#include "Texture2D.h"
|
#include "Texture2D.h"
|
||||||
#include "Timer.h"
|
|
||||||
#include "UniformBuffer.h"
|
#include "UniformBuffer.h"
|
||||||
#include "Vertex.h"
|
|
||||||
#include "VertexBuffer.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
|
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
|
class Application final
|
||||||
{
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Application);
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Instance> instance;
|
std::unique_ptr<Instance> instance;
|
||||||
std::unique_ptr<Pipeline> graphicsPipeline;
|
std::unique_ptr<Pipeline> graphicsPipeline;
|
||||||
@@ -78,164 +33,21 @@ namespace Copium
|
|||||||
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
|
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application()
|
Application();
|
||||||
{
|
~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 (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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool Update();
|
||||||
private:
|
private:
|
||||||
|
void InitializeInstance();
|
||||||
void InitializeInstance()
|
void InitializeFrameBuffer();
|
||||||
{
|
void InitializeTextureSampler();
|
||||||
instance = std::make_unique<Instance>("Copium Engine");
|
void InitializeUniformBuffer();
|
||||||
}
|
void InitializeDescriptorSets();
|
||||||
|
void InitializeGraphicsPipeline();
|
||||||
void InitializeFrameBuffer()
|
void InitializeVertexBuffer();
|
||||||
{
|
void InitializeIndexBuffer();
|
||||||
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
|
void InitializeCommandBuffer();
|
||||||
}
|
void RecordCommandBuffer();
|
||||||
|
void UpdateUniformBuffer();
|
||||||
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->AddSampler(*texture2D, 1);
|
|
||||||
|
|
||||||
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
|
|
||||||
descriptorSetPassthrough->AddSampler(framebuffer->GetColorAttachment(), 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();
|
|
||||||
|
|
||||||
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), 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,139 @@
|
|||||||
|
#include "Buffer.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Buffer::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), "Buffer : 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), "Buffer : Failed to allocate buffer memory");
|
||||||
|
|
||||||
|
vkBindBufferMemory(instance.GetDevice(), handle, memory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::~Buffer()
|
||||||
|
{
|
||||||
|
vkFreeMemory(instance.GetDevice(), memory, nullptr);
|
||||||
|
vkDestroyBuffer(instance.GetDevice(), handle, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::Update(void* indexData, int index)
|
||||||
|
{
|
||||||
|
CP_ASSERT(index >= 0 && index < count, "Update : 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 Buffer::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 Buffer::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* Buffer::Map()
|
||||||
|
{
|
||||||
|
CP_ASSERT(mappedData == nullptr, "Map : Mapping an already mapped buffer");
|
||||||
|
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
||||||
|
return mappedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::Unmap()
|
||||||
|
{
|
||||||
|
CP_ASSERT(mappedData != nullptr, "Unmap : Unmapping an already unmapped buffer");
|
||||||
|
|
||||||
|
vkUnmapMemory(instance.GetDevice(), memory);
|
||||||
|
mappedData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::operator VkBuffer() const
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize Buffer::GetSize() const
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize Buffer::GetPosition(int index) const
|
||||||
|
{
|
||||||
|
CP_ASSERT(index >= 0 && index < count, "GetPosition : Index is outside of the buffer");
|
||||||
|
return size * (VkDeviceSize)index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::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), "CopyBuffer : 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, dstBuffer, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-145
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include <optional>
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
@@ -21,153 +21,20 @@ namespace Copium
|
|||||||
void* mappedData = nullptr;
|
void* mappedData = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Buffer(Instance& instance, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDeviceSize size, int count)
|
Buffer(Instance& instance, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDeviceSize size, int count);
|
||||||
: instance{instance}, size{size}, count{count}
|
virtual ~Buffer();
|
||||||
{
|
|
||||||
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), "Buffer : Failed to initialize buffer");
|
void Update(void* indexData, int index);
|
||||||
|
void UpdateStaging(void* data);
|
||||||
|
void UpdateStaging(void* data, VkDeviceSize offset, VkDeviceSize size);
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements;
|
void* Map();
|
||||||
vkGetBufferMemoryRequirements(instance.GetDevice(), handle, &memoryRequirements);
|
void Unmap();
|
||||||
|
|
||||||
VkMemoryAllocateInfo allocateInfo{};
|
operator VkBuffer() const;
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
VkDeviceSize GetSize() const;
|
||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
VkDeviceSize GetPosition(int index) const;
|
||||||
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Buffer : Failed to allocate buffer memory");
|
static void CopyBuffer(Instance& instance, const Buffer& srcBuffer, const Buffer& dstBuffer, VkDeviceSize offset, VkDeviceSize size);
|
||||||
|
|
||||||
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, "Update : 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, "Map : Mapping an already mapped buffer");
|
|
||||||
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
|
||||||
return mappedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unmap()
|
|
||||||
{
|
|
||||||
CP_ASSERT(mappedData != nullptr, "Unmap : Unmapping an already unmapped buffer");
|
|
||||||
|
|
||||||
vkUnmapMemory(instance.GetDevice(), memory);
|
|
||||||
mappedData = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); };
|
|
||||||
|
|
||||||
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &handle, &offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BindAsIndexBuffer(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
// TODO: Maybe don't assume that indices are uint16?
|
|
||||||
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBuffer GetHandle() const
|
|
||||||
{
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize GetSize() const
|
|
||||||
{
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize GetPosition(int index) const
|
|
||||||
{
|
|
||||||
CP_ASSERT(index >= 0 && index < count, "GetPosition : 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), "CopyBuffer : 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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "ColorAttachment.h"
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
ColorAttachment::ColorAttachment(Instance& instance, int width, int height)
|
||||||
|
: Sampler{instance}
|
||||||
|
{
|
||||||
|
InitializeColorAttachment(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorAttachment::~ColorAttachment()
|
||||||
|
{
|
||||||
|
for (auto&& image : images)
|
||||||
|
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
||||||
|
for (auto&& imageMemory : imageMemories)
|
||||||
|
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
||||||
|
for (auto&& imageView : imageViews)
|
||||||
|
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo ColorAttachment::GetDescriptorImageInfo(int index) const
|
||||||
|
{
|
||||||
|
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for color attachment");
|
||||||
|
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.sampler = sampler;
|
||||||
|
imageInfo.imageView = imageViews[index];
|
||||||
|
return imageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView ColorAttachment::GetImageView(int index)
|
||||||
|
{
|
||||||
|
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetImageView : Index out of bound");
|
||||||
|
|
||||||
|
return imageViews[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorAttachment::InitializeColorAttachment(int width, int height)
|
||||||
|
{
|
||||||
|
images.resize(instance.GetMaxFramesInFlight());
|
||||||
|
imageMemories.resize(instance.GetMaxFramesInFlight());
|
||||||
|
imageViews.resize(instance.GetMaxFramesInFlight());
|
||||||
|
for (size_t i = 0; i < images.size(); i++)
|
||||||
|
{
|
||||||
|
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
|
||||||
|
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Image.h"
|
|
||||||
#include "Sampler.h"
|
#include "Sampler.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class ColorAttachment : public Sampler
|
class ColorAttachment final : public Sampler
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(ColorAttachment);
|
CP_DELETE_COPY_AND_MOVE_CTOR(ColorAttachment);
|
||||||
private:
|
private:
|
||||||
@@ -15,51 +16,13 @@ namespace Copium
|
|||||||
std::vector<VkDeviceMemory> imageMemories;
|
std::vector<VkDeviceMemory> imageMemories;
|
||||||
std::vector<VkImageView> imageViews;
|
std::vector<VkImageView> imageViews;
|
||||||
public:
|
public:
|
||||||
ColorAttachment(Instance& instance, int width, int height)
|
ColorAttachment(Instance& instance, int width, int height);
|
||||||
: Sampler{instance}
|
~ColorAttachment() override;
|
||||||
{
|
|
||||||
InitializeColorAttachment(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
~ColorAttachment() override
|
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
|
||||||
{
|
VkImageView GetImageView(int index);
|
||||||
for (auto&& image : images)
|
|
||||||
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
|
||||||
for (auto&& imageMemory : imageMemories)
|
|
||||||
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
|
||||||
for (auto&& imageView : imageViews)
|
|
||||||
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override
|
|
||||||
{
|
|
||||||
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for color attachment");
|
|
||||||
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.sampler = sampler;
|
|
||||||
imageInfo.imageView = imageViews[index];
|
|
||||||
return imageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView GetImageView(int index)
|
|
||||||
{
|
|
||||||
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetImageView : Index out of bound");
|
|
||||||
|
|
||||||
return imageViews[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeColorAttachment(int width, int height)
|
void InitializeColorAttachment(int width, int height);
|
||||||
{
|
|
||||||
images.resize(instance.GetMaxFramesInFlight());
|
|
||||||
imageMemories.resize(instance.GetMaxFramesInFlight());
|
|
||||||
imageViews.resize(instance.GetMaxFramesInFlight());
|
|
||||||
for (size_t i = 0; i < images.size(); i++)
|
|
||||||
{
|
|
||||||
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
|
|
||||||
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#include "CommandBuffer.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
CommandBuffer::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()), "CommandBuffer : Failed to allocate CommandBuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBuffer::~CommandBuffer()
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test as constexpr function to see if it avoids the switch case
|
||||||
|
void CommandBuffer::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_ABORT("Begin : Unreachable switch case");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkResetCommandBuffer(currentCommandBuffer, 0);
|
||||||
|
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Begin : Failed to begin command buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandBuffer::End()
|
||||||
|
{
|
||||||
|
vkEndCommandBuffer(currentCommandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandBuffer::Submit()
|
||||||
|
{
|
||||||
|
VkSubmitInfo submitInfo{};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = ¤tCommandBuffer;
|
||||||
|
|
||||||
|
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
|
||||||
|
// TODO: if singleUse?
|
||||||
|
vkQueueWaitIdle(instance.GetGraphicsQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandBuffer::SubmitAsGraphicsQueue()
|
||||||
|
{
|
||||||
|
instance.SubmitGraphicsQueue({currentCommandBuffer});
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBuffer::operator VkCommandBuffer() const
|
||||||
|
{
|
||||||
|
return currentCommandBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
@@ -22,81 +23,15 @@ namespace Copium
|
|||||||
VkCommandBuffer currentCommandBuffer{VK_NULL_HANDLE};
|
VkCommandBuffer currentCommandBuffer{VK_NULL_HANDLE};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandBuffer(Instance& instance, Type type)
|
CommandBuffer(Instance& instance, Type type);
|
||||||
: instance{instance}, type{type}
|
|
||||||
{
|
|
||||||
if (type == Type::Dynamic)
|
|
||||||
commandBuffers.resize(instance.GetMaxFramesInFlight());
|
|
||||||
else
|
|
||||||
commandBuffers.resize(1);
|
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocateInfo{};
|
virtual ~CommandBuffer();
|
||||||
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()), "CommandBuffer : Failed to allocate CommandBuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
~CommandBuffer()
|
void Begin();
|
||||||
{
|
void End();
|
||||||
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
|
void Submit();
|
||||||
}
|
void SubmitAsGraphicsQueue();
|
||||||
|
|
||||||
operator VkCommandBuffer() const
|
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)
|
|
||||||
{
|
|
||||||
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_ABORT("Begin : Unreachable switch case");
|
|
||||||
}
|
|
||||||
|
|
||||||
vkResetCommandBuffer(currentCommandBuffer, 0);
|
|
||||||
CP_VK_ASSERT(vkBeginCommandBuffer(currentCommandBuffer, &beginInfo), "Begin : Failed to begin command buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
void End()
|
|
||||||
{
|
|
||||||
vkEndCommandBuffer(currentCommandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Submit()
|
|
||||||
{
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = ¤tCommandBuffer;
|
|
||||||
|
|
||||||
vkQueueSubmit(instance.GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
|
|
||||||
// TODO: if singleUse?
|
|
||||||
vkQueueWaitIdle(instance.GetGraphicsQueue());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubmitAsGraphicsQueue()
|
|
||||||
{
|
|
||||||
instance.SubmitGraphicsQueue({currentCommandBuffer});
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer GetHandle() const
|
|
||||||
{
|
|
||||||
return currentCommandBuffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include "CommandBufferScoped.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
CommandBufferScoped::CommandBufferScoped(Instance& instance)
|
||||||
|
: CommandBuffer{instance, Type::SingleUse}
|
||||||
|
{
|
||||||
|
CommandBuffer::Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBufferScoped::~CommandBufferScoped()
|
||||||
|
{
|
||||||
|
CommandBuffer::End();
|
||||||
|
CommandBuffer::Submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,20 +5,12 @@
|
|||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class CommandBufferScoped : public CommandBuffer
|
class CommandBufferScoped final : public CommandBuffer
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBufferScoped);
|
CP_DELETE_COPY_AND_MOVE_CTOR(CommandBufferScoped);
|
||||||
public:
|
public:
|
||||||
CommandBufferScoped(Instance& instance)
|
CommandBufferScoped(Instance& instance);
|
||||||
: CommandBuffer{instance, Type::SingleUse}
|
|
||||||
{
|
|
||||||
CommandBuffer::Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
~CommandBufferScoped()
|
~CommandBufferScoped() override;
|
||||||
{
|
|
||||||
CommandBuffer::End();
|
|
||||||
CommandBuffer::Submit();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@
|
|||||||
throw VulkanException(Copium::StringFormat(format, __VA_ARGS__)); \
|
throw VulkanException(Copium::StringFormat(format, __VA_ARGS__)); \
|
||||||
} \
|
} \
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
|
#define CP_STATIC_CLASS(ClassName)\
|
||||||
|
ClassName() = delete
|
||||||
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
||||||
ClassName(ClassName&&) = delete; \
|
ClassName(ClassName&&) = delete; \
|
||||||
ClassName(const ClassName&) = delete; \
|
ClassName(const ClassName&) = delete; \
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include "DebugMessenger.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DebugMessenger::DebugMessenger(VkInstance 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+13
-61
@@ -1,89 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
|
|
||||||
class DebugMessenger
|
class DebugMessenger final
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
|
CP_DELETE_COPY_AND_MOVE_CTOR(DebugMessenger);
|
||||||
public:
|
public:
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
VkDebugUtilsMessengerEXT debugMessenger;
|
VkDebugUtilsMessengerEXT debugMessenger;
|
||||||
|
|
||||||
DebugMessenger(VkInstance instance)
|
DebugMessenger(VkInstance instance);
|
||||||
: instance{instance}
|
~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), "DebugMessenger : Failed to initialze debug messenger");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
~DebugMessenger()
|
static void AddRequiredExtensions(std::vector<const char*>* extensions);
|
||||||
{
|
static void AddRequiredLayers(std::vector<const char*>* layers);
|
||||||
#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:
|
private:
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void* pUserData)
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
static VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator,
|
const VkAllocationCallbacks* pAllocator,
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
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,
|
static void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
VkDebugUtilsMessengerEXT debugMessenger,
|
VkDebugUtilsMessengerEXT debugMessenger,
|
||||||
const VkAllocationCallbacks* pAllocator) {
|
const VkAllocationCallbacks* pAllocator);
|
||||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
||||||
if (func != nullptr) {
|
|
||||||
func(instance, debugMessenger, pAllocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "DepthAttachment.h"
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
DepthAttachment::DepthAttachment(Instance& instance, int width, int height)
|
||||||
|
: Sampler{instance}
|
||||||
|
{
|
||||||
|
InitializeDepthAttachment(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
DepthAttachment::~DepthAttachment()
|
||||||
|
{
|
||||||
|
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
||||||
|
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
||||||
|
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo DepthAttachment::GetDescriptorImageInfo(int index) const
|
||||||
|
{
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.sampler = sampler;
|
||||||
|
imageInfo.imageView = imageView;
|
||||||
|
return imageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView DepthAttachment::GetImageView() const
|
||||||
|
{
|
||||||
|
return imageView;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthAttachment::InitializeDepthAttachment(int width, int height)
|
||||||
|
{
|
||||||
|
VkFormat depthFormat = Image::SelectDepthFormat(instance);
|
||||||
|
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
||||||
|
imageView = Image::InitializeImageView(instance, image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Image.h"
|
|
||||||
#include "Sampler.h"
|
#include "Sampler.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class DepthAttachment : public Sampler
|
class DepthAttachment final : public Sampler
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(DepthAttachment);
|
CP_DELETE_COPY_AND_MOVE_CTOR(DepthAttachment);
|
||||||
private:
|
private:
|
||||||
@@ -15,39 +16,14 @@ namespace Copium
|
|||||||
VkDeviceMemory imageMemory;
|
VkDeviceMemory imageMemory;
|
||||||
VkImageView imageView;
|
VkImageView imageView;
|
||||||
public:
|
public:
|
||||||
DepthAttachment(Instance& instance, int width, int height)
|
DepthAttachment(Instance& instance, int width, int height);
|
||||||
: Sampler{instance}
|
~DepthAttachment() override;
|
||||||
{
|
|
||||||
InitializeDepthAttachment(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DepthAttachment() override
|
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
|
||||||
{
|
VkImageView GetImageView() const;
|
||||||
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
|
||||||
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
|
||||||
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override
|
|
||||||
{
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.sampler = sampler;
|
|
||||||
imageInfo.imageView = imageView;
|
|
||||||
return imageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView GetImageView() const
|
|
||||||
{
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeDepthAttachment(int width, int height)
|
void InitializeDepthAttachment(int width, int height);
|
||||||
{
|
|
||||||
VkFormat depthFormat = Image::SelectDepthFormat(instance);
|
|
||||||
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
|
||||||
imageView = Image::InitializeImageView(instance, image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#include "DescriptorPool.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
DescriptorPool::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?
|
||||||
|
|
||||||
|
poolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
|
poolSizes[1].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;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "DescriptorPool : Failed to initialize descriptor pool");
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorPool::~DescriptorPool()
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSet> DescriptorPool::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();
|
||||||
|
|
||||||
|
descriptorSets.resize(instance.GetMaxFramesInFlight());
|
||||||
|
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "AllocateDescriptorSets : Failed to allocate descriptor sets");
|
||||||
|
|
||||||
|
return descriptorSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorPool::FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
|
||||||
|
{
|
||||||
|
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
@@ -15,50 +16,10 @@ namespace Copium
|
|||||||
VkDescriptorPool descriptorPool;
|
VkDescriptorPool descriptorPool;
|
||||||
static const int DESCRIPTOR_SET_COUNT = 100;
|
static const int DESCRIPTOR_SET_COUNT = 100;
|
||||||
public:
|
public:
|
||||||
DescriptorPool(Instance& instance)
|
DescriptorPool(Instance& instance);
|
||||||
: instance{instance}
|
~DescriptorPool();
|
||||||
{
|
|
||||||
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?
|
|
||||||
|
|
||||||
poolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
std::vector<VkDescriptorSet> AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout);
|
||||||
poolSizes[1].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
|
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "DescriptorPool : Failed to initialize descriptor pool");
|
|
||||||
}
|
|
||||||
|
|
||||||
~DescriptorPool()
|
|
||||||
{
|
|
||||||
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
descriptorSets.resize(instance.GetMaxFramesInFlight());
|
|
||||||
CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "AllocateDescriptorSets : Failed to allocate descriptor sets");
|
|
||||||
|
|
||||||
return descriptorSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
|
|
||||||
{
|
|
||||||
vkFreeDescriptorSets(instance.GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#include "DescriptorSet.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
DescriptorSet::DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout)
|
||||||
|
: instance{instance}, descriptorPool{descriptorPool}, descriptorSetLayout{descriptorSetLayout}
|
||||||
|
{
|
||||||
|
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorSet::~DescriptorSet()
|
||||||
|
{
|
||||||
|
descriptorPool.FreeDescriptorSets(descriptorSets);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorSet::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 DescriptorSet::AddSampler(const Sampler& sampler, uint32_t binding)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
||||||
|
VkDescriptorImageInfo imageInfo = sampler.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::operator VkDescriptorSet() const
|
||||||
|
{
|
||||||
|
return descriptorSets[instance.GetFlightIndex()];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,57 +20,11 @@ namespace Copium
|
|||||||
std::vector<VkDescriptorSet> descriptorSets;
|
std::vector<VkDescriptorSet> descriptorSets;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout)
|
DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout);
|
||||||
: instance{instance}, descriptorPool{descriptorPool}, descriptorSetLayout{descriptorSetLayout}
|
~DescriptorSet();
|
||||||
{
|
|
||||||
descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DescriptorSet()
|
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding);
|
||||||
{
|
void AddSampler(const Sampler& sampler, uint32_t binding);
|
||||||
descriptorPool.FreeDescriptorSets(descriptorSets);
|
operator VkDescriptorSet() const;
|
||||||
}
|
|
||||||
|
|
||||||
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 AddSampler(const Sampler& sampler, uint32_t binding)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
|
||||||
VkDescriptorImageInfo imageInfo = sampler.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()];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
std::vector<char> FileSystem::ReadFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "ReadFile : Failed to open file");
|
||||||
|
|
||||||
|
size_t fileSize = (size_t)file.tellg();
|
||||||
|
std::vector<char> buffer(fileSize);
|
||||||
|
|
||||||
|
file.seekg(0);
|
||||||
|
file.read(buffer.data(), fileSize);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileSystem::ReadFileStr(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "ReadFileStr : Failed to open file");
|
||||||
|
|
||||||
|
size_t fileSize = (size_t)file.tellg();
|
||||||
|
std::string buffer;
|
||||||
|
buffer.resize(fileSize);
|
||||||
|
|
||||||
|
file.seekg(0);
|
||||||
|
file.read(buffer.data(), fileSize);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::WriteFile(const std::string& filename, const std::string& data)
|
||||||
|
{
|
||||||
|
std::filesystem::path path{filename};
|
||||||
|
std::filesystem::create_directories(path.parent_path());
|
||||||
|
std::ofstream file(filename, std::ios::binary);
|
||||||
|
CP_ASSERT(file.is_open(), "WriteFile : Failed to open file");
|
||||||
|
|
||||||
|
file.write(data.c_str(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::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(), "WriteFile : Failed to open file");
|
||||||
|
|
||||||
|
file.write(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::FileExists(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename);
|
||||||
|
return file.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t FileSystem::DateModified(const std::string& filename)
|
||||||
|
{
|
||||||
|
struct stat result;
|
||||||
|
CP_ASSERT(stat(filename.c_str(), &result) == 0, "DataModified : Cannot stat file %s", filename.c_str());
|
||||||
|
return (int64_t)result.st_mtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-62
@@ -12,68 +12,13 @@ namespace Copium
|
|||||||
{
|
{
|
||||||
class FileSystem
|
class FileSystem
|
||||||
{
|
{
|
||||||
FileSystem() = delete;
|
CP_STATIC_CLASS(FileSystem);
|
||||||
public:
|
public:
|
||||||
static std::vector<char> ReadFile(const std::string& filename)
|
static std::vector<char> ReadFile(const std::string& filename);
|
||||||
{
|
static std::string ReadFileStr(const std::string& filename);
|
||||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
static void WriteFile(const std::string& filename, const std::string& data);
|
||||||
CP_ASSERT(file.is_open(), "ReadFile : Failed to open file");
|
static void WriteFile(const std::string& filename, const char* data, size_t size);
|
||||||
|
static bool FileExists(const std::string& filename);
|
||||||
size_t fileSize = (size_t)file.tellg();
|
static int64_t DateModified(const std::string& filename);
|
||||||
std::vector<char> buffer(fileSize);
|
|
||||||
|
|
||||||
file.seekg(0);
|
|
||||||
file.read(buffer.data(), fileSize);
|
|
||||||
|
|
||||||
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(), "ReadFileStr : Failed to open file");
|
|
||||||
|
|
||||||
size_t fileSize = (size_t)file.tellg();
|
|
||||||
std::string buffer;
|
|
||||||
buffer.resize(fileSize);
|
|
||||||
|
|
||||||
file.seekg(0);
|
|
||||||
file.read(buffer.data(), fileSize);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteFile(const std::string& filename, const std::string& data)
|
|
||||||
{
|
|
||||||
std::filesystem::path path{filename};
|
|
||||||
std::filesystem::create_directories(path.parent_path());
|
|
||||||
std::ofstream file(filename, std::ios::binary);
|
|
||||||
CP_ASSERT(file.is_open(), "WriteFile : Failed to open file");
|
|
||||||
|
|
||||||
file.write(data.c_str(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteFile(const std::string& filename, const char* data, size_t size)
|
|
||||||
{
|
|
||||||
std::filesystem::path path{filename};
|
|
||||||
std::filesystem::create_directories(path.parent_path());
|
|
||||||
std::ofstream file(filename, std::ios::binary);
|
|
||||||
CP_ASSERT(file.is_open(), "WriteFile : Failed to open file");
|
|
||||||
|
|
||||||
file.write(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool FileExists(const std::string& filename)
|
|
||||||
{
|
|
||||||
std::ifstream file(filename);
|
|
||||||
return file.good();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t DateModified(const std::string& filename)
|
|
||||||
{
|
|
||||||
struct stat result;
|
|
||||||
CP_ASSERT(stat(filename.c_str(), &result) == 0, "DataModified : Cannot stat file %s", filename.c_str());
|
|
||||||
return (int64_t)result.st_mtime;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
#include "Framebuffer.h"
|
||||||
|
|
||||||
|
#include "CommandBuffer.h"
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Framebuffer::Framebuffer(Instance& instance, uint32_t width, uint32_t height)
|
||||||
|
: instance{instance}, width{width}, height{height}
|
||||||
|
{
|
||||||
|
InitializeImage();
|
||||||
|
InitializeDepthBuffer();
|
||||||
|
InitializeRenderPass();
|
||||||
|
InitializeFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
Framebuffer::~Framebuffer()
|
||||||
|
{
|
||||||
|
for (auto& framebuffer : framebuffers)
|
||||||
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
|
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::Resize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
vkDeviceWaitIdle(instance.GetDevice());
|
||||||
|
this->width = width;
|
||||||
|
this->height = height;
|
||||||
|
colorAttachment.reset();
|
||||||
|
depthAttachment.reset();
|
||||||
|
for (auto&& framebuffer : framebuffers)
|
||||||
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
|
InitializeImage();
|
||||||
|
InitializeDepthBuffer();
|
||||||
|
InitializeFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::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);
|
||||||
|
|
||||||
|
VkViewport viewport{};
|
||||||
|
viewport.x = 0.0f;
|
||||||
|
viewport.y = 0.0f;
|
||||||
|
viewport.width = width;
|
||||||
|
viewport.height = height;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
VkRect2D scissor{};
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = {width, height};
|
||||||
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::Unbind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPass Framebuffer::GetRenderPass() const
|
||||||
|
{
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFramebuffer Framebuffer::GetFramebuffer() const
|
||||||
|
{
|
||||||
|
return framebuffers[instance.GetFlightIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorAttachment& Framebuffer::GetColorAttachment() const
|
||||||
|
{
|
||||||
|
return *colorAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Framebuffer::GetWidth() const
|
||||||
|
{
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Framebuffer::GetHeight() const
|
||||||
|
{
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::InitializeImage()
|
||||||
|
{
|
||||||
|
colorAttachment = std::make_unique<ColorAttachment>(instance, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::InitializeDepthBuffer()
|
||||||
|
{
|
||||||
|
depthAttachment = std::make_unique<DepthAttachment>(instance, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::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 Framebuffer::InitializeFramebuffers()
|
||||||
|
{
|
||||||
|
framebuffers.resize(instance.GetMaxFramesInFlight());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<VkImageView> attachments{colorAttachment->GetImageView(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 = width;
|
||||||
|
createInfo.height = height;
|
||||||
|
createInfo.layers = 1;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize framebuffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-184
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Image.h"
|
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "ColorAttachment.h"
|
#include "ColorAttachment.h"
|
||||||
#include "DepthAttachment.h"
|
#include "DepthAttachment.h"
|
||||||
@@ -10,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class Framebuffer
|
class Framebuffer final
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
|
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
|
||||||
private:
|
private:
|
||||||
@@ -24,191 +23,23 @@ namespace Copium
|
|||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
public:
|
public:
|
||||||
Framebuffer(Instance& instance, uint32_t width, uint32_t height)
|
Framebuffer(Instance& instance, uint32_t width, uint32_t height);
|
||||||
: instance{instance}, width{width}, height{height}
|
~Framebuffer();
|
||||||
{
|
|
||||||
InitializeImage();
|
|
||||||
InitializeDepthBuffer();
|
|
||||||
InitializeRenderPass();
|
|
||||||
InitializeFramebuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Framebuffer()
|
void Resize(uint32_t width, uint32_t height);
|
||||||
{
|
void Bind(const CommandBuffer& commandBuffer);
|
||||||
for (auto& framebuffer : framebuffers)
|
void Unbind(const CommandBuffer& commandBuffer);
|
||||||
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
|
||||||
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize(uint32_t width, uint32_t height)
|
VkRenderPass GetRenderPass() const;
|
||||||
{
|
VkFramebuffer GetFramebuffer() const;
|
||||||
vkDeviceWaitIdle(instance.GetDevice());
|
const ColorAttachment& GetColorAttachment() const;
|
||||||
this->width = width;
|
uint32_t GetWidth() const;
|
||||||
this->height = height;
|
uint32_t GetHeight() const;
|
||||||
colorAttachment.reset();
|
|
||||||
depthAttachment.reset();
|
|
||||||
for (auto&& framebuffer : framebuffers)
|
|
||||||
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
|
||||||
InitializeImage();
|
|
||||||
InitializeDepthBuffer();
|
|
||||||
InitializeFramebuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
VkViewport viewport{};
|
|
||||||
viewport.x = 0.0f;
|
|
||||||
viewport.y = 0.0f;
|
|
||||||
viewport.width = width;
|
|
||||||
viewport.height = height;
|
|
||||||
viewport.minDepth = 0.0f;
|
|
||||||
viewport.maxDepth = 1.0f;
|
|
||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
|
||||||
VkRect2D scissor{};
|
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = {width, height};
|
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unbind(const CommandBuffer& commandBuffer)
|
|
||||||
{
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkRenderPass GetRenderPass() const
|
|
||||||
{
|
|
||||||
return renderPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFramebuffer GetFramebuffer() const
|
|
||||||
{
|
|
||||||
return framebuffers[instance.GetFlightIndex()];
|
|
||||||
}
|
|
||||||
|
|
||||||
const ColorAttachment& GetColorAttachment() const
|
|
||||||
{
|
|
||||||
return *colorAttachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetWidth() const
|
|
||||||
{
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetHeight() const
|
|
||||||
{
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void InitializeImage();
|
||||||
void InitializeImage()
|
void InitializeDepthBuffer();
|
||||||
{
|
void InitializeRenderPass();
|
||||||
colorAttachment = std::make_unique<ColorAttachment>(instance, width, height);
|
void InitializeFramebuffers();
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeDepthBuffer()
|
|
||||||
{
|
|
||||||
depthAttachment = std::make_unique<DepthAttachment>(instance, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
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{colorAttachment->GetImageView(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 = width;
|
|
||||||
createInfo.height = height;
|
|
||||||
createInfo.layers = 1;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize framebuffer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include "CommandBufferScoped.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
void Image::InitializeImage(Instance& instance, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* imageMemory)
|
||||||
|
{
|
||||||
|
VkImageCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
createInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
createInfo.extent.width = width;
|
||||||
|
createInfo.extent.height = height;
|
||||||
|
createInfo.extent.depth = 1;
|
||||||
|
createInfo.mipLevels = 1;
|
||||||
|
createInfo.arrayLayers = 1;
|
||||||
|
createInfo.format = format;
|
||||||
|
createInfo.tiling = tiling;
|
||||||
|
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
createInfo.usage = usage;
|
||||||
|
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
createInfo.flags = 0;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "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);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView Image::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::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, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkFormat Image::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::HasStencilComponent(VkFormat format)
|
||||||
|
{
|
||||||
|
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFormat Image::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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-172
@@ -1,187 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "CommandBufferScoped.h"
|
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class Image
|
class Image
|
||||||
{
|
{
|
||||||
Image() = delete;
|
CP_STATIC_CLASS(Image);
|
||||||
public:
|
public:
|
||||||
static void InitializeImage(Instance& instance, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* imageMemory)
|
static void InitializeImage(Instance& instance, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* imageMemory);
|
||||||
{
|
static VkImageView InitializeImageView(Instance& instance, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags);
|
||||||
VkImageCreateInfo createInfo{};
|
static void TransitionImageLayout(Instance& instance, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height);
|
||||||
createInfo.imageType = VK_IMAGE_TYPE_2D;
|
static VkFormat SelectDepthFormat(Instance& instance);
|
||||||
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
|
|
||||||
{
|
|
||||||
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, ®ion);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
private:
|
||||||
static bool HasStencilComponent(VkFormat format)
|
static bool HasStencilComponent(VkFormat format);
|
||||||
{
|
static VkFormat SelectSupportedFormat(Instance& instance, const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||||
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");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include "IndexBuffer.h"
|
||||||
|
|
||||||
|
#include "CommandBuffer.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
IndexBuffer::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 IndexBuffer::Bind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexBuffer::Draw(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class IndexBuffer : public Buffer
|
class IndexBuffer final : public Buffer
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(IndexBuffer);
|
CP_DELETE_COPY_AND_MOVE_CTOR(IndexBuffer);
|
||||||
private:
|
private:
|
||||||
int indexCount;
|
int indexCount;
|
||||||
public:
|
public:
|
||||||
IndexBuffer(Instance& instance, int indexCount)
|
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
|
void Bind(const CommandBuffer& commandBuffer);
|
||||||
{
|
void Draw(const CommandBuffer& commandBuffer);
|
||||||
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Draw(const CommandBuffer& commandBuffer)
|
|
||||||
{
|
|
||||||
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,408 @@
|
|||||||
|
#include "Instance.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");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkInstance Instance::GetInstance() const
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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>(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
-401
@@ -41,410 +41,40 @@ namespace Copium
|
|||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Instance(const std::string& applicationName)
|
Instance(const std::string& applicationName);
|
||||||
{
|
~Instance();
|
||||||
timer.Start();
|
bool BeginPresent();
|
||||||
InitializeWindow(applicationName);
|
bool EndPresent();
|
||||||
InitializeInstance(applicationName);
|
void SubmitGraphicsQueue(const std::vector<VkCommandBuffer>& commandBuffers);
|
||||||
InitializeDebugMessenger();
|
VkInstance GetInstance() const;
|
||||||
InitializeSurface();
|
GLFWwindow* GetWindow() const;
|
||||||
SelectPhysicalDevice();
|
VkSurfaceKHR GetSurface() const;
|
||||||
InitializeLogicalDevice();
|
VkPhysicalDevice GetPhysicalDevice() const;
|
||||||
InitializeCommandPool();
|
VkDevice GetDevice() const;
|
||||||
InitializeSwapChain();
|
VkCommandPool GetCommandPool() const;
|
||||||
InitializeSyncObjects();
|
VkQueue GetGraphicsQueue() const;
|
||||||
CP_INFO("Instance : Initialized Vulkan in %f seconds", timer.Elapsed());
|
int GetFlightIndex() const;
|
||||||
}
|
int GetMaxFramesInFlight() const;
|
||||||
|
const SwapChain& GetSwapChain() const;
|
||||||
~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 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]), "SubmitGraphicsQueue : 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
|
// TODO: Create Device class and move this there
|
||||||
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
|
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;
|
|
||||||
}
|
|
||||||
CP_ABORT("FindMemoryType : Failed to find suitable memory type");
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeWindow(const std::string& applicationName)
|
void InitializeWindow(const std::string& applicationName);
|
||||||
{
|
void InitializeInstance(const std::string& applicationName);
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
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);
|
||||||
|
|
||||||
|
|
||||||
#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 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 InitializeDebugMessenger()
|
|
||||||
{
|
|
||||||
debugMessenger = std::make_unique<DebugMessenger>(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeSurface()
|
|
||||||
{
|
|
||||||
CP_VK_ASSERT(glfwCreateWindowSurface(instance, window, nullptr, &surface), "InitializeSurface : Failed to create Vulkan surface");
|
|
||||||
}
|
|
||||||
|
|
||||||
void 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 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 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), "InitializeCommandPool : 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]), "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*> 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("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 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
#include "Pipeline.h"
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "Shader.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Pipeline::Pipeline(Instance& instance, PipelineCreator creator)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
InitializeDescriptorSetLayout(creator);
|
||||||
|
InitializePipeline(creator);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline::~Pipeline()
|
||||||
|
{
|
||||||
|
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
|
||||||
|
for (auto&& descriptorSetLayout : descriptorSetLayouts)
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipeline::Bind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipeline::SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
|
||||||
|
{
|
||||||
|
CP_ASSERT(setIndex < boundDescriptorSets.size(), "SetDescriptorSet : DescriptorSet index is out of bounds");
|
||||||
|
boundDescriptorSets[setIndex] = descriptorSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipeline::BindDescriptorSets(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, boundDescriptorSets.size(), boundDescriptorSets.data(), 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayout Pipeline::GetDescriptorSetLayout(uint32_t setIndex) const
|
||||||
|
{
|
||||||
|
return descriptorSetLayouts[setIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipeline::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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++]), "InitializeDescriptorSetLayout : Failed to initialize descriptor set layout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipeline::InitializePipeline(const PipelineCreator& creator)
|
||||||
|
{
|
||||||
|
Shader shader{instance, Shader::Type::GlslFile, creator.vertexShader, creator.fragmentShader};
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
|
||||||
|
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
inputAssemblyCreateInfo.topology = creator.topology;
|
||||||
|
inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkViewport viewport{};
|
||||||
|
viewport.x = 0;
|
||||||
|
viewport.y = 0;
|
||||||
|
viewport.width = 1;
|
||||||
|
viewport.height = 1;
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
VkRect2D scissor{};
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = {1, 1};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "InitializePipeline : 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;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "InitializePipeline : Failed to initialize graphics pipeline");
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-206
@@ -1,19 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "CommandBuffer.h"
|
#include "CommandBuffer.h"
|
||||||
#include "Instance.h"
|
#include "Common.h"
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "DescriptorSet.h"
|
#include "DescriptorSet.h"
|
||||||
|
#include "Instance.h"
|
||||||
#include "PipelineCreator.h"
|
#include "PipelineCreator.h"
|
||||||
#include "Shader.h"
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class Pipeline
|
class Pipeline final
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Pipeline);
|
CP_DELETE_COPY_AND_MOVE_CTOR(Pipeline);
|
||||||
private:
|
private:
|
||||||
@@ -25,207 +23,15 @@ namespace Copium
|
|||||||
VkPipeline graphicsPipeline;
|
VkPipeline graphicsPipeline;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Pipeline(Instance& instance, PipelineCreator creator)
|
Pipeline(Instance& instance, PipelineCreator creator);
|
||||||
: instance{instance}
|
~Pipeline();
|
||||||
{
|
void Bind(const CommandBuffer& commandBuffer);
|
||||||
InitializeDescriptorSetLayout(creator);
|
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet);
|
||||||
InitializePipeline(creator);
|
void BindDescriptorSets(const CommandBuffer& commandBuffer);
|
||||||
}
|
VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const;
|
||||||
|
|
||||||
~Pipeline()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
|
|
||||||
for (auto&& descriptorSetLayout : descriptorSetLayouts)
|
|
||||||
{
|
|
||||||
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bind(const CommandBuffer& commandBuffer)
|
|
||||||
{
|
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetDescriptorSet(uint32_t setIndex, const DescriptorSet& descriptorSet)
|
|
||||||
{
|
|
||||||
CP_ASSERT(setIndex < boundDescriptorSets.size(), "SetDescriptorSet : 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:
|
private:
|
||||||
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
|
void InitializeDescriptorSetLayout(const PipelineCreator& creator);
|
||||||
{
|
void InitializePipeline(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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
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++]), "InitializeDescriptorSetLayout : Failed to initialize descriptor set layout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializePipeline(const PipelineCreator& creator)
|
|
||||||
{
|
|
||||||
Shader shader{instance, Shader::Type::GlslFile, creator.vertexShader, creator.fragmentShader};
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
|
|
||||||
inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
||||||
inputAssemblyCreateInfo.topology = creator.topology;
|
|
||||||
inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
|
|
||||||
|
|
||||||
VkViewport viewport{};
|
|
||||||
viewport.x = 0;
|
|
||||||
viewport.y = 0;
|
|
||||||
viewport.width = 1;
|
|
||||||
viewport.height = 1;
|
|
||||||
viewport.minDepth = 0.0f;
|
|
||||||
viewport.maxDepth = 1.0f;
|
|
||||||
|
|
||||||
VkRect2D scissor{};
|
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = {1, 1};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreatePipelineLayout(instance.GetDevice(), &pipelineLayoutCreateInfo, nullptr, &pipelineLayout), "InitializePipeline : 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;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateGraphicsPipelines(instance.GetDevice(), VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &graphicsPipeline), "InitializePipeline : Failed to initialize graphics pipeline");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include "PipelineCreator.h"
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
PipelineCreator::PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
|
||||||
|
: vertexShader{vertexShader},
|
||||||
|
fragmentShader{fragmentShader},
|
||||||
|
renderPass{renderPass}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void PipelineCreator::SetVertexDescriptor(const VertexDescriptor& descriptor)
|
||||||
|
{
|
||||||
|
vertexDescriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineCreator::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 PipelineCreator::SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
||||||
|
{
|
||||||
|
topology = primitiveTopology;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineCreator::SetCullMode(VkCullModeFlags flags)
|
||||||
|
{
|
||||||
|
cullMode = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineCreator::SetCullFrontFace(VkFrontFace cullFrontFace)
|
||||||
|
{
|
||||||
|
frontFace = cullFrontFace;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "VertexDescriptor.h"
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
@@ -30,34 +30,12 @@ namespace Copium
|
|||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
|
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader);
|
||||||
: vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass}
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SetVertexDescriptor(const VertexDescriptor& descriptor)
|
void SetVertexDescriptor(const VertexDescriptor& descriptor);
|
||||||
{
|
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags);
|
||||||
vertexDescriptor = descriptor;
|
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology);
|
||||||
}
|
void SetCullMode(VkCullModeFlags flags);
|
||||||
|
void SetCullFrontFace(VkFrontFace cullFrontFace);
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
@@ -11,33 +10,8 @@ namespace Copium
|
|||||||
std::optional<uint32_t> graphicsFamily;
|
std::optional<uint32_t> graphicsFamily;
|
||||||
std::optional<uint32_t> presentFamily;
|
std::optional<uint32_t> presentFamily;
|
||||||
|
|
||||||
QueueFamiliesQuery(VkSurfaceKHR surface, VkPhysicalDevice device)
|
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;
|
bool AllRequiredFamiliesSupported();
|
||||||
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 AllRequiredFamiliesSupported()
|
|
||||||
{
|
|
||||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "Sampler.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Sampler::Sampler(Instance& instance)
|
||||||
|
: instance{instance}
|
||||||
|
{
|
||||||
|
InitializeSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sampler::~Sampler()
|
||||||
|
{
|
||||||
|
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sampler::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");
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-35
@@ -14,42 +14,11 @@ namespace Copium
|
|||||||
Instance& instance;
|
Instance& instance;
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
public:
|
public:
|
||||||
Sampler(Instance& instance)
|
Sampler(Instance& instance);
|
||||||
: instance{instance}
|
virtual ~Sampler();
|
||||||
{
|
|
||||||
InitializeSampler();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Sampler()
|
|
||||||
{
|
|
||||||
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeSampler()
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
|
||||||
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
|
|
||||||
|
|
||||||
VkSamplerCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
createInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.anisotropyEnable = VK_TRUE;
|
|
||||||
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
|
||||||
createInfo.unnormalizedCoordinates = VK_FALSE;
|
|
||||||
createInfo.compareEnable = VK_FALSE;
|
|
||||||
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
createInfo.mipLodBias = 0.0f;
|
|
||||||
createInfo.minLod = 0.0f;
|
|
||||||
createInfo.maxLod = 0.0f;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "InitializeSampler : Failed to initialize texture sampler");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual VkDescriptorImageInfo GetDescriptorImageInfo(int index) const = 0;
|
virtual VkDescriptorImageInfo GetDescriptorImageInfo(int index) const = 0;
|
||||||
|
private:
|
||||||
|
void InitializeSampler();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#include "Shader.h"
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Shader::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, "Shader : 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::~Shader()
|
||||||
|
{
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), vertShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(instance.GetDevice(), fragShaderModule, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VkPipelineShaderStageCreateInfo> Shader::GetShaderStages() const
|
||||||
|
{
|
||||||
|
return shaderStages;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule Shader::InitializeShaderModule(const std::vector<uint32_t>& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(codeSpv.data(), codeSpv.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule Shader::InitializeShaderModule(const std::string& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(reinterpret_cast<const uint32_t*>(codeSpv.data()), codeSpv.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule Shader::InitializeShaderModule(const std::vector<char>& codeSpv)
|
||||||
|
{
|
||||||
|
return InitializeShaderModule(reinterpret_cast<const uint32_t*>(codeSpv.data()), codeSpv.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule Shader::InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind type)
|
||||||
|
{
|
||||||
|
std::string spvFilename = ".cache/" + filename + ".spv";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (FileSystem::FileExists(spvFilename))
|
||||||
|
{
|
||||||
|
if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename))
|
||||||
|
{
|
||||||
|
CP_DEBUG("InitializeShaderModuleFromGlslFile : 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("InitializeShaderModuleFromGlslFile : Cached shader file is invalid, recreating it");
|
||||||
|
}
|
||||||
|
CP_DEBUG("InitializeShaderModuleFromGlslFile : 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, "InitializeShaderModuleFromGlslFile : Failed to compile shader: %s\n%s", filename.c_str(), result.GetErrorMessage().c_str());
|
||||||
|
|
||||||
|
std::vector<uint32_t> data{result.cbegin(), result.cend()};
|
||||||
|
FileSystem::WriteFile(spvFilename, (const char*)data.data(), data.size() * sizeof(uint32_t));
|
||||||
|
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule Shader::InitializeShaderModuleFromGlslCode(const std::string& code, shaderc_shader_kind type)
|
||||||
|
{
|
||||||
|
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, "InitializeShaderModuleFromGlslCode : 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 Shader::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), "InitializeShaderModule : Failed to initialize shader module");
|
||||||
|
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-127
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
#include <shaderc/shaderc.hpp>
|
#include <shaderc/shaderc.hpp>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class Shader
|
class Shader final
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Shader);
|
CP_DELETE_COPY_AND_MOVE_CTOR(Shader);
|
||||||
public:
|
public:
|
||||||
@@ -24,132 +23,16 @@ namespace Copium
|
|||||||
VkShaderModule fragShaderModule;
|
VkShaderModule fragShaderModule;
|
||||||
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||||
public:
|
public:
|
||||||
Shader(Instance& instance, Type type, const std::string& vertexInput, const std::string& fragmentInput)
|
Shader(Instance& instance, Type type, const std::string& vertexInput, const std::string& fragmentInput);
|
||||||
: instance{instance}
|
~Shader();
|
||||||
{
|
|
||||||
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, "Shader : 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
~Shader()
|
|
||||||
{
|
|
||||||
vkDestroyShaderModule(instance.GetDevice(), vertShaderModule, nullptr);
|
|
||||||
vkDestroyShaderModule(instance.GetDevice(), fragShaderModule, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<VkPipelineShaderStageCreateInfo> GetShaderStages() const
|
|
||||||
{
|
|
||||||
return shaderStages;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const std::vector<VkPipelineShaderStageCreateInfo> GetShaderStages() const;
|
||||||
private:
|
private:
|
||||||
VkShaderModule InitializeShaderModule(const std::vector<uint32_t>& codeSpv)
|
VkShaderModule InitializeShaderModule(const std::vector<uint32_t>& codeSpv);
|
||||||
{
|
VkShaderModule InitializeShaderModule(const std::string& codeSpv);
|
||||||
return InitializeShaderModule(codeSpv.data(), codeSpv.size() * sizeof(uint32_t));
|
VkShaderModule InitializeShaderModule(const std::vector<char>& codeSpv);
|
||||||
}
|
VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind type);
|
||||||
|
VkShaderModule InitializeShaderModuleFromGlslCode(const std::string& code, shaderc_shader_kind type);
|
||||||
VkShaderModule InitializeShaderModule(const std::string& codeSpv)
|
VkShaderModule InitializeShaderModule(const uint32_t* data, size_t size);
|
||||||
{
|
|
||||||
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::FileExists(spvFilename))
|
|
||||||
{
|
|
||||||
if (FileSystem::DateModified(filename) < FileSystem::DateModified(spvFilename))
|
|
||||||
{
|
|
||||||
CP_DEBUG("InitializeShaderModuleFromGlslFile : 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("InitializeShaderModuleFromGlslFile : Cached shader file is invalid, recreating it");
|
|
||||||
}
|
|
||||||
CP_DEBUG("InitializeShaderModuleFromGlslFile : 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, "InitializeShaderModuleFromGlslFile : Failed to compile shader: %s\n%s", filename.c_str(), result.GetErrorMessage().c_str());
|
|
||||||
|
|
||||||
std::vector<uint32_t> data{result.cbegin(), result.cend()};
|
|
||||||
FileSystem::WriteFile(spvFilename, (const char*)data.data(), data.size() * sizeof(uint32_t));
|
|
||||||
return InitializeShaderModule(data.data(), data.size() * sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderModule InitializeShaderModuleFromGlslCode(const std::string& code, shaderc_shader_kind type)
|
|
||||||
{
|
|
||||||
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, "InitializeShaderModuleFromGlslCode : 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), "InitializeShaderModule : Failed to initialize shader module");
|
|
||||||
|
|
||||||
return shaderModule;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class Texture2D : public Sampler
|
class Texture2D final : public Sampler
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
|
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
Timer::Timer()
|
||||||
|
: startTime{std::chrono::steady_clock::now()}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Timer::Start()
|
||||||
|
{
|
||||||
|
startTime = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Timer::Elapsed()
|
||||||
|
{
|
||||||
|
return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-12
@@ -9,18 +9,9 @@ namespace Copium
|
|||||||
private:
|
private:
|
||||||
std::chrono::time_point<std::chrono::steady_clock> startTime;
|
std::chrono::time_point<std::chrono::steady_clock> startTime;
|
||||||
public:
|
public:
|
||||||
Timer()
|
Timer();
|
||||||
: startTime{std::chrono::steady_clock::now()}
|
|
||||||
{}
|
|
||||||
|
|
||||||
void Start()
|
void Start();
|
||||||
{
|
double Elapsed();
|
||||||
startTime = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
double Elapsed()
|
|
||||||
{
|
|
||||||
return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#include "UniformBuffer.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
UniformBuffer::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()}
|
||||||
|
{}
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo UniformBuffer::GetDescriptorBufferInfo(int index) const
|
||||||
|
{
|
||||||
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
bufferInfo.buffer = handle;
|
||||||
|
bufferInfo.offset = (VkDeviceSize)index * size;
|
||||||
|
bufferInfo.range = size;
|
||||||
|
return bufferInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-16
@@ -1,34 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class UniformBuffer : public Buffer
|
class UniformBuffer final : public Buffer
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
|
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UniformBuffer(Instance& instance, VkDeviceSize size)
|
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()}
|
|
||||||
{}
|
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Update(const T& t)
|
void Update(const T& t);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void UniformBuffer::Update(const T& t)
|
||||||
{
|
{
|
||||||
CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Update : Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize());
|
CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Update : Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize());
|
||||||
Buffer::Update((void*)&t, instance.GetFlightIndex());
|
Buffer::Update((void*)&t, instance.GetFlightIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
|
|
||||||
{
|
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
|
||||||
bufferInfo.buffer = handle;
|
|
||||||
bufferInfo.offset = (VkDeviceSize)index * size;
|
|
||||||
bufferInfo.range = size;
|
|
||||||
return bufferInfo;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "Vertex.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
VertexDescriptor Vertex::GetDescriptor()
|
||||||
|
{
|
||||||
|
VertexDescriptor descriptor{};
|
||||||
|
descriptor.AddAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos), sizeof(Vertex));
|
||||||
|
descriptor.AddAttribute(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color), sizeof(Vertex));
|
||||||
|
descriptor.AddAttribute(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord), sizeof(Vertex));
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-10
@@ -1,24 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
#include "VertexDescriptor.h"
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
struct Vertex {
|
struct Vertex
|
||||||
|
{
|
||||||
glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
glm::vec2 texCoord;
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
static VertexDescriptor GetDescriptor()
|
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "VertexBuffer.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
VertexBuffer::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}
|
||||||
|
{
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
for (auto&& binding : descriptor.GetBindings())
|
||||||
|
{
|
||||||
|
bindingOffsets.emplace_back(offset);
|
||||||
|
bindingSizes.emplace_back(binding.stride * vertexCount);
|
||||||
|
offset += binding.stride * vertexCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::Bind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::Update(uint32_t binding, void* data)
|
||||||
|
{
|
||||||
|
UpdateStaging(data, bindingOffsets[binding], bindingSizes[binding]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "CommandBuffer.h"
|
||||||
|
#include "Instance.h"
|
||||||
#include "VertexDescriptor.h"
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class VertexBuffer : public Buffer
|
class VertexBuffer final : public Buffer
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(VertexBuffer);
|
CP_DELETE_COPY_AND_MOVE_CTOR(VertexBuffer);
|
||||||
private:
|
private:
|
||||||
std::vector<VkDeviceSize> bindingOffsets;
|
std::vector<VkDeviceSize> bindingOffsets;
|
||||||
std::vector<VkDeviceSize> bindingSizes;
|
std::vector<VkDeviceSize> bindingSizes;
|
||||||
public:
|
public:
|
||||||
VertexBuffer(Instance& instance, const VertexDescriptor& descriptor, int vertexCount)
|
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}
|
|
||||||
{
|
|
||||||
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
|
void Bind(const CommandBuffer& commandBuffer);
|
||||||
{
|
void Update(uint32_t binding, void* data);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
void VertexDescriptor::AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset, uint32_t size)
|
||||||
|
{
|
||||||
|
CP_ASSERT(binding <= bindings.size(), "AddAttribute : Attribute binding must less than or be equal to the amount of current bindings");
|
||||||
|
|
||||||
|
if (binding == bindings.size())
|
||||||
|
AddLayout(binding, size);
|
||||||
|
|
||||||
|
VkVertexInputAttributeDescription description{};
|
||||||
|
description.binding = binding;
|
||||||
|
description.location = location;
|
||||||
|
description.format = format;
|
||||||
|
description.offset = offset;
|
||||||
|
attributes.emplace_back(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize VertexDescriptor::GetVertexSize() const
|
||||||
|
{
|
||||||
|
VkDeviceSize bufferSize = 0;
|
||||||
|
for (auto&& binding : bindings)
|
||||||
|
{
|
||||||
|
bufferSize += binding.stride;
|
||||||
|
}
|
||||||
|
return bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VkVertexInputAttributeDescription>& VertexDescriptor::GetAttributes() const
|
||||||
|
{
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VkVertexInputBindingDescription>& VertexDescriptor::GetBindings() const
|
||||||
|
{
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VertexDescriptor::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <vector>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
class VertexDescriptor
|
class VertexDescriptor
|
||||||
@@ -12,51 +13,12 @@ namespace Copium
|
|||||||
std::vector<VkVertexInputAttributeDescription> attributes;
|
std::vector<VkVertexInputAttributeDescription> attributes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset, uint32_t size);
|
||||||
void AddAttribute(uint32_t binding, uint32_t location, VkFormat format, uint32_t offset)
|
VkDeviceSize GetVertexSize() const;
|
||||||
{
|
const std::vector<VkVertexInputAttributeDescription>& GetAttributes() const;
|
||||||
CP_ASSERT(binding <= bindings.size(), "AddAttribute : Attribute binding must less than or be equal to the amount of current bindings");
|
const std::vector<VkVertexInputBindingDescription>& GetBindings() const;
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
bufferSize += binding.stride;
|
|
||||||
}
|
|
||||||
return bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<VkVertexInputAttributeDescription>& GetAttributes() const
|
|
||||||
{
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<VkVertexInputBindingDescription>& GetBindings() const
|
|
||||||
{
|
|
||||||
return bindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t AddLayout(uint32_t binding, uint32_t size)
|
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "VertexPassthrough.h"
|
||||||
|
|
||||||
|
namespace Copium
|
||||||
|
{
|
||||||
|
VertexDescriptor VertexPassthrough::GetDescriptor()
|
||||||
|
{
|
||||||
|
VertexDescriptor descriptor{};
|
||||||
|
descriptor.AddAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough, texCoord), sizeof(VertexPassthrough));
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
#include "VertexDescriptor.h"
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
namespace Copium
|
namespace Copium
|
||||||
{
|
{
|
||||||
struct VertexPassthrough {
|
struct VertexPassthrough
|
||||||
|
{
|
||||||
glm::vec2 texCoord;
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
static VertexDescriptor GetDescriptor()
|
static VertexDescriptor GetDescriptor();
|
||||||
{
|
|
||||||
VertexDescriptor descriptor{};
|
|
||||||
descriptor.AddAttribute<VertexPassthrough>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough, texCoord));
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user