diff --git a/Syndra/src/Engine/Renderer/Buffer.cpp b/Syndra/src/Engine/Renderer/Buffer.cpp index 9fccf64..7b3906c 100644 --- a/Syndra/src/Engine/Renderer/Buffer.cpp +++ b/Syndra/src/Engine/Renderer/Buffer.cpp @@ -2,6 +2,7 @@ #include "Engine/Renderer/Buffer.h" #include "Engine/Renderer/Renderer.h" #include "Platform/OpenGL/OpenGLBuffer.h" +#include "Platform/Vulkan/VulkanBuffer.h" namespace Syndra { @@ -15,6 +16,8 @@ namespace Syndra { return nullptr; case RendererAPI::API::OpenGL: return CreateRef(vertices, size); + case RendererAPI::API::Vulkan: + return CreateRef(vertices, size); } SN_CORE_ASSERT(false, "Unknown API!"); @@ -30,10 +33,12 @@ namespace Syndra { return nullptr; case RendererAPI::API::OpenGL: return CreateRef(vertices, count); + case RendererAPI::API::Vulkan: + return CreateRef(vertices, count); } SN_CORE_ASSERT(false, "Unknown API!"); return nullptr; } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/DeferredRenderer.cpp b/Syndra/src/Engine/Renderer/DeferredRenderer.cpp index 13c3f62..5bda47a 100644 --- a/Syndra/src/Engine/Renderer/DeferredRenderer.cpp +++ b/Syndra/src/Engine/Renderer/DeferredRenderer.cpp @@ -4,17 +4,24 @@ #include "imgui_internal.h" #include "Engine/Utils/PlatformUtils.h" #include "Engine/Core/Application.h" +#include "Engine/Renderer/Renderer.h" #include "Engine/Scene/Entity.h" #include "Engine/Scene/Scene.h" #include namespace Syndra { - + static bool IsVulkan() + { + return Renderer::GetAPI() == RendererAPI::API::Vulkan; + } + static DeferredRenderer::RenderData r_Data; void DeferredRenderer::Init(const Ref& scene, const ShaderLibrary& shaders, const Ref& env) { + if (IsVulkan()) + return; r_Data.scene = scene; r_Data.shaders = shaders; r_Data.environment = env; @@ -132,6 +139,8 @@ namespace Syndra { void DeferredRenderer::Render() { + if (IsVulkan()) + return; auto view = r_Data.scene->m_Registry.view(); //---------------------------------------------------------SHADOW PASS------------------------------------------// r_Data.shadowPass->BindTargetFrameBuffer(); @@ -193,6 +202,8 @@ namespace Syndra { void DeferredRenderer::End() { + if (IsVulkan()) + return; //-------------------------------------------------Lighting and post-processing pass---------------------------------------------------// r_Data.lightingPass->BindTargetFrameBuffer(); @@ -260,12 +271,16 @@ namespace Syndra { Renderer::EndScene(); } - void DeferredRenderer::ShutDown() - { - } +void DeferredRenderer::ShutDown() +{ + if (IsVulkan()) + return; +} void DeferredRenderer::OnImGuiRender(bool* rendererOpen, bool* environmentOpen) { + if (IsVulkan()) + return; //Renderer settings if (*rendererOpen) { ImGui::Begin(ICON_FA_COGS" Renderer Settings", rendererOpen); @@ -397,16 +412,20 @@ namespace Syndra { } } - void DeferredRenderer::OnResize(uint32_t width, uint32_t height) - { - r_Data.geoPass->GetSpecification().TargetFrameBuffer->Resize(width, height); +void DeferredRenderer::OnResize(uint32_t width, uint32_t height) +{ + if (IsVulkan()) + return; + r_Data.geoPass->GetSpecification().TargetFrameBuffer->Resize(width, height); r_Data.lightingPass->GetSpecification().TargetFrameBuffer->Resize(width, height); r_Data.aaPass->GetSpecification().TargetFrameBuffer->Resize(width, height); } - void DeferredRenderer::UpdateLights() - { - r_Data.lightManager->IntitializeLights(); +void DeferredRenderer::UpdateLights() +{ + if (IsVulkan()) + return; + r_Data.lightManager->IntitializeLights(); auto viewLights = r_Data.scene->m_Registry.view(); //point light index int pIndex = 0; @@ -448,10 +467,12 @@ namespace Syndra { r_Data.lightManager->UpdateBuffer(); } - uint32_t DeferredRenderer::GetFinalTextureID(int index) - { - if (r_Data.useFxaa) { - return r_Data.aaPass->GetSpecification().TargetFrameBuffer->GetColorAttachmentRendererID(index); +uint32_t DeferredRenderer::GetFinalTextureID(int index) +{ + if (IsVulkan()) + return 0; + if (r_Data.useFxaa) { + return r_Data.aaPass->GetSpecification().TargetFrameBuffer->GetColorAttachmentRendererID(index); } else { @@ -459,14 +480,18 @@ namespace Syndra { } } - uint32_t DeferredRenderer::GetMouseTextureID() - { - return 4; - } +uint32_t DeferredRenderer::GetMouseTextureID() +{ + if (IsVulkan()) + return 0; + return 4; +} - Ref DeferredRenderer::GetMainFrameBuffer() - { - return r_Data.geoPass->GetSpecification().TargetFrameBuffer; - } +Ref DeferredRenderer::GetMainFrameBuffer() +{ + if (IsVulkan()) + return nullptr; + return r_Data.geoPass->GetSpecification().TargetFrameBuffer; +} } diff --git a/Syndra/src/Engine/Renderer/Environment.cpp b/Syndra/src/Engine/Renderer/Environment.cpp index 6e00350..76977e4 100644 --- a/Syndra/src/Engine/Renderer/Environment.cpp +++ b/Syndra/src/Engine/Renderer/Environment.cpp @@ -1,5 +1,6 @@ #include "lpch.h" #include "Engine/Renderer/Environment.h" +#include "Engine/Renderer/Renderer.h" #include "glad/glad.h" namespace Syndra { @@ -7,6 +8,8 @@ namespace Syndra { Environment::Environment(const Ref& hdri) :m_HDRSkyMap(hdri) { + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + return; m_EquirectangularToCube = Shader::Create("assets/shaders/EquirectangularToCube.glsl"); m_BackgroundShader = Shader::Create("assets/shaders/BackgroundSky.glsl"); m_PrefilterShader = Shader::Create("assets/shaders/Prefilter.glsl"); @@ -199,21 +202,27 @@ namespace Syndra { } - void Environment::RenderCube() - { - m_CubeVAO->Bind(); - glDrawArrays(GL_TRIANGLES, 0, 36); - } - - void Environment::RenderQuad() - { - m_QuadVAO->Bind(); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - } - - void Environment::RenderBackground() - { - m_BackgroundShader->Bind(); +void Environment::RenderCube() +{ + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + return; + m_CubeVAO->Bind(); + glDrawArrays(GL_TRIANGLES, 0, 36); +} + +void Environment::RenderQuad() +{ + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + return; + m_QuadVAO->Bind(); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); +} + +void Environment::RenderBackground() +{ + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + return; + m_BackgroundShader->Bind(); Texture2D::BindTexture(envCubemap, 0); //Texture2D::BindTexture(m_IrradianceFBO->GetColorAttachmentRendererID(), 1); m_BackgroundShader->SetMat4("cam.view", m_View); @@ -222,9 +231,11 @@ namespace Syndra { m_BackgroundShader->Unbind(); } - void Environment::SetIntensity(float intensity) - { - m_BackgroundShader->Bind(); +void Environment::SetIntensity(float intensity) +{ + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + return; + m_BackgroundShader->Bind(); m_BackgroundShader->SetFloat("push.intensity", intensity); m_BackgroundShader->Unbind(); } @@ -323,4 +334,4 @@ namespace Syndra { //m_IrradianceFBO = FrameBuffer::Create(spec); } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/ForwardPlusRenderer.cpp b/Syndra/src/Engine/Renderer/ForwardPlusRenderer.cpp index 4706df1..aab1f00 100644 --- a/Syndra/src/Engine/Renderer/ForwardPlusRenderer.cpp +++ b/Syndra/src/Engine/Renderer/ForwardPlusRenderer.cpp @@ -7,15 +7,22 @@ #include "Engine/Scene/Entity.h" #include "Engine/Scene/Scene.h" #include "Engine/Core/Instrument.h" +#include "Engine/Renderer/Renderer.h" #include namespace Syndra { + static bool IsVulkan() + { + return Renderer::GetAPI() == RendererAPI::API::Vulkan; + } static ForwardPlusRenderer::RenderData r_Data; - void ForwardPlusRenderer::Init(const Ref& scene, const ShaderLibrary& shaders, const Ref& env) - { - r_Data.scene = scene; +void ForwardPlusRenderer::Init(const Ref& scene, const ShaderLibrary& shaders, const Ref& env) +{ + if (IsVulkan()) + return; + r_Data.scene = scene; r_Data.shaders = shaders; r_Data.environment = env; @@ -136,9 +143,11 @@ namespace Syndra { r_Data.ShadowBuffer = UniformBuffer::Create(sizeof(glm::mat4), 3); } - void ForwardPlusRenderer::Render() - { - auto view = r_Data.scene->m_Registry.view(); +void ForwardPlusRenderer::Render() +{ + if (IsVulkan()) + return; + auto view = r_Data.scene->m_Registry.view(); //-----------------------------------------------Depth Pre Pass--------------------------------------------// { SN_PROFILE_SCOPE("Depth pass"); @@ -267,9 +276,11 @@ namespace Syndra { } } - void ForwardPlusRenderer::End() - { - //-------------------------------------Post Processing and Depth Debug------------------------------------// +void ForwardPlusRenderer::End() +{ + if (IsVulkan()) + return; + //-------------------------------------Post Processing and Depth Debug------------------------------------// { SN_PROFILE_SCOPE("Post Processing"); r_Data.postProcPass->BindTargetFrameBuffer(); @@ -287,15 +298,19 @@ namespace Syndra { } } - void ForwardPlusRenderer::ShutDown() - { - glDeleteBuffers(1, &r_Data.lightBuffer); - glDeleteBuffers(1, &r_Data.visibleLightIndicesBuffer); - } - - void ForwardPlusRenderer::SetupLights() - { - glCreateBuffers(1, &r_Data.lightBuffer); +void ForwardPlusRenderer::ShutDown() +{ + if (IsVulkan()) + return; + glDeleteBuffers(1, &r_Data.lightBuffer); + glDeleteBuffers(1, &r_Data.visibleLightIndicesBuffer); +} + +void ForwardPlusRenderer::SetupLights() +{ + if (IsVulkan()) + return; + glCreateBuffers(1, &r_Data.lightBuffer); glCreateBuffers(1, &r_Data.visibleLightIndicesBuffer); //creating and binding point light buffer @@ -318,9 +333,11 @@ namespace Syndra { glNamedBufferSubData(r_Data.lightBuffer, 0, sizeof(r_Data.pLights), &r_Data.pLights); } - void ForwardPlusRenderer::UpdateLights() - { - SN_PROFILE_FUNCTION(); +void ForwardPlusRenderer::UpdateLights() +{ + if (IsVulkan()) + return; + SN_PROFILE_FUNCTION(); auto viewLights = r_Data.scene->m_Registry.view(); //point light index int pIndex = 0; @@ -379,27 +396,35 @@ namespace Syndra { glNamedBufferSubData(r_Data.lightBuffer, 0, sizeof(r_Data.pLights), &r_Data.pLights); } - uint32_t ForwardPlusRenderer::GetFinalTextureID(int index) - { - return r_Data.postProcPass->GetSpecification().TargetFrameBuffer->GetColorAttachmentRendererID(0); +uint32_t ForwardPlusRenderer::GetFinalTextureID(int index) +{ + if (IsVulkan()) + return 0; + return r_Data.postProcPass->GetSpecification().TargetFrameBuffer->GetColorAttachmentRendererID(0); //return r_Data.lightingPass->GetSpecification().TargetFrameBuffer->GetColorAttachmentRendererID(0); } - uint32_t ForwardPlusRenderer::GetMouseTextureID() - { - return 2; - } - - Ref ForwardPlusRenderer::GetMainFrameBuffer() - { - //TODO - //Fix attachment ID - return r_Data.lightingPass->GetSpecification().TargetFrameBuffer; - } - - void ForwardPlusRenderer::OnImGuiRender(bool* rendererOpen, bool* environmentOpen) - { - if (*rendererOpen) { +uint32_t ForwardPlusRenderer::GetMouseTextureID() +{ + if (IsVulkan()) + return 0; + return 2; +} + +Ref ForwardPlusRenderer::GetMainFrameBuffer() +{ + if (IsVulkan()) + return nullptr; + //TODO + //Fix attachment ID + return r_Data.lightingPass->GetSpecification().TargetFrameBuffer; +} + +void ForwardPlusRenderer::OnImGuiRender(bool* rendererOpen, bool* environmentOpen) +{ + if (IsVulkan()) + return; + if (*rendererOpen) { ImGui::Begin(ICON_FA_COGS" Renderer Settings", rendererOpen); ImGui::Text("ForwardPlus debugger"); static bool showDepth = false; @@ -504,9 +529,11 @@ namespace Syndra { } } - void ForwardPlusRenderer::OnResize(uint32_t width, uint32_t height) - { - r_Data.depthPass->GetSpecification().TargetFrameBuffer->Resize(width, height); +void ForwardPlusRenderer::OnResize(uint32_t width, uint32_t height) +{ + if (IsVulkan()) + return; + r_Data.depthPass->GetSpecification().TargetFrameBuffer->Resize(width, height); r_Data.lightingPass->GetSpecification().TargetFrameBuffer->Resize(width, height); r_Data.postProcPass->GetSpecification().TargetFrameBuffer->Resize(width, height); //change the number of work groups in the compute shader @@ -519,4 +546,4 @@ namespace Syndra { glNamedBufferSubData(r_Data.visibleLightIndicesBuffer, 0, numberOfTiles * sizeof(VisibleIndex) * r_Data.numLights, nullptr); } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/FrameBuffer.cpp b/Syndra/src/Engine/Renderer/FrameBuffer.cpp index 19569a4..7066653 100644 --- a/Syndra/src/Engine/Renderer/FrameBuffer.cpp +++ b/Syndra/src/Engine/Renderer/FrameBuffer.cpp @@ -2,6 +2,7 @@ #include "Engine/Renderer/FrameBuffer.h" #include "Engine/Renderer/Renderer.h" #include "Platform/OpenGL/OpenGLFrameBuffer.h" +#include "Platform/Vulkan/VulkanFrameBuffer.h" namespace Syndra { @@ -14,10 +15,12 @@ namespace Syndra { return nullptr; case RendererAPI::API::OpenGL: return CreateRef(spec); + case RendererAPI::API::Vulkan: + return CreateRef(spec); } SN_CORE_ASSERT(false, "Unknown API!"); return nullptr; } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/RenderCommand.cpp b/Syndra/src/Engine/Renderer/RenderCommand.cpp index 9b302e2..11f4586 100644 --- a/Syndra/src/Engine/Renderer/RenderCommand.cpp +++ b/Syndra/src/Engine/Renderer/RenderCommand.cpp @@ -1,9 +1,20 @@ #include "lpch.h" #include "Engine/Renderer/RenderCommand.h" #include "Platform/OpenGL/OpenGLRendererAPI.h" +#include "Platform/Vulkan/VulkanRendererAPI.h" namespace Syndra { - RendererAPI* RenderCommand::s_RendererAPI = new OpenGLRendererAPI; + RendererAPI* RenderCommand::s_RendererAPI = []() -> RendererAPI* + { + switch (RendererAPI::GetAPI()) + { + case RendererAPI::API::Vulkan: + return new VulkanRendererAPI(); + case RendererAPI::API::OpenGL: + default: + return new OpenGLRendererAPI(); + } + }(); -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/Renderer.cpp b/Syndra/src/Engine/Renderer/Renderer.cpp index 522944c..3b76b0e 100644 --- a/Syndra/src/Engine/Renderer/Renderer.cpp +++ b/Syndra/src/Engine/Renderer/Renderer.cpp @@ -1,7 +1,6 @@ #include "lpch.h" #include "Engine/Renderer/Renderer.h" #include "Engine/Renderer/RenderCommand.h" -#include namespace Syndra { Renderer::SceneData* Renderer::m_SceneData = new Renderer::SceneData; @@ -77,4 +76,4 @@ namespace Syndra { return RenderCommand::GetInfo(); } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/RendererAPI.cpp b/Syndra/src/Engine/Renderer/RendererAPI.cpp index 6a0cb33..71765e4 100644 --- a/Syndra/src/Engine/Renderer/RendererAPI.cpp +++ b/Syndra/src/Engine/Renderer/RendererAPI.cpp @@ -3,6 +3,6 @@ namespace Syndra { - RendererAPI::API RendererAPI::s_API = RendererAPI::API::OpenGL; + RendererAPI::API RendererAPI::s_API = RendererAPI::API::Vulkan; -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/RendererAPI.h b/Syndra/src/Engine/Renderer/RendererAPI.h index 720049b..bdf1db9 100644 --- a/Syndra/src/Engine/Renderer/RendererAPI.h +++ b/Syndra/src/Engine/Renderer/RendererAPI.h @@ -17,7 +17,8 @@ namespace Syndra { public: enum class API { NONE = 0, - OpenGL = 1 + OpenGL = 1, + Vulkan = 2 }; public: @@ -38,4 +39,4 @@ namespace Syndra { static API s_API; }; -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/SceneRenderer.cpp b/Syndra/src/Engine/Renderer/SceneRenderer.cpp index e94e1d4..f2f0ab8 100644 --- a/Syndra/src/Engine/Renderer/SceneRenderer.cpp +++ b/Syndra/src/Engine/Renderer/SceneRenderer.cpp @@ -6,16 +6,21 @@ #include "Engine/Scene/Scene.h" #include "imgui.h" #include "imgui_internal.h" +#include "Engine/Renderer/Renderer.h" #include namespace Syndra { static SceneRenderer::SceneData s_Data; - - void SceneRenderer::Initialize() + static bool IsVulkan() { - //s_Data.renderPipeline = CreateRef(); - s_Data.renderPipeline = CreateRef(); + return Renderer::GetAPI() == RendererAPI::API::Vulkan; + } + +void SceneRenderer::Initialize() +{ + //s_Data.renderPipeline = CreateRef(); + s_Data.renderPipeline = CreateRef(); //Initializing the pipeline s_Data.renderPipeline->Init(s_Data.scene, s_Data.shaders, s_Data.environment); @@ -48,10 +53,12 @@ namespace Syndra { s_Data.scene->m_Shaders = s_Data.shaders; } - void SceneRenderer::InitializeEnvironment() - { - //Initializing the environment map - auto path = s_Data.scene->m_EnvironmentPath; +void SceneRenderer::InitializeEnvironment() +{ + if (IsVulkan()) + return; + //Initializing the environment map + auto path = s_Data.scene->m_EnvironmentPath; if (s_Data.environment) { s_Data.scene->m_EnvironmentPath = s_Data.environment->GetPath(); } diff --git a/Syndra/src/Engine/Renderer/Shader.cpp b/Syndra/src/Engine/Renderer/Shader.cpp index 8b11e82..34ec338 100644 --- a/Syndra/src/Engine/Renderer/Shader.cpp +++ b/Syndra/src/Engine/Renderer/Shader.cpp @@ -2,7 +2,7 @@ #include "Engine/Renderer/Shader.h" #include "Engine/Renderer/Renderer.h" #include "Platform/OpenGL/OpenGLShader.h" -#include "glad/glad.h" +#include "Platform/Vulkan/VulkanShader.h" namespace Syndra { @@ -12,6 +12,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(filepath); + case RendererAPI::API::Vulkan: return CreateRef(filepath); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -24,6 +25,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(name, vertexSrc, fragmentSrc); + case RendererAPI::API::Vulkan: return CreateRef(name, vertexSrc, fragmentSrc); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -76,4 +78,3 @@ namespace Syndra { } - diff --git a/Syndra/src/Engine/Renderer/Texture.cpp b/Syndra/src/Engine/Renderer/Texture.cpp index dfa1374..9f44753 100644 --- a/Syndra/src/Engine/Renderer/Texture.cpp +++ b/Syndra/src/Engine/Renderer/Texture.cpp @@ -3,6 +3,7 @@ #include "Engine/Renderer/Renderer.h" #include "Platform/OpenGL/OpenGLTexture2D.h" #include "Platform/OpenGL/OpenGLTexture1D.h" +#include "Platform/Vulkan/VulkanTexture2D.h" namespace Syndra { @@ -12,6 +13,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(width, height); + case RendererAPI::API::Vulkan: return CreateRef(width, height); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -24,6 +26,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(path,sRGB,false); + case RendererAPI::API::Vulkan: return CreateRef(path, sRGB,false); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -36,6 +39,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(width,height,data,sRGB); + case RendererAPI::API::Vulkan: return CreateRef(width, height, data, sRGB); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -48,6 +52,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(path, sRGB, HDR); + case RendererAPI::API::Vulkan: return CreateRef(path, sRGB, HDR); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); @@ -60,6 +65,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); case RendererAPI::API::OpenGL: OpenGLTexture2D::BindTexture(rendererID,slot); + case RendererAPI::API::Vulkan: break; } @@ -71,6 +77,7 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(size); + case RendererAPI::API::Vulkan: return CreateRef(size); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); return nullptr; @@ -82,9 +89,10 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(size,data); + case RendererAPI::API::Vulkan: return CreateRef(size, data); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); return nullptr; } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/UniformBuffer.cpp b/Syndra/src/Engine/Renderer/UniformBuffer.cpp index bc86888..0abb0a6 100644 --- a/Syndra/src/Engine/Renderer/UniformBuffer.cpp +++ b/Syndra/src/Engine/Renderer/UniformBuffer.cpp @@ -3,6 +3,7 @@ #include "Engine/Renderer/Renderer.h" #include "Platform/OpenGL/OpenGLUniformBuffer.h" +#include "Platform/Vulkan/VulkanUniformBuffer.h" namespace Syndra { @@ -12,10 +13,11 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::None is currently not supported!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(size, binding); + case RendererAPI::API::Vulkan: return CreateRef(size, binding); } SN_CORE_ASSERT(false, "Unknown RendererAPI!"); return nullptr; } -} \ No newline at end of file +} diff --git a/Syndra/src/Engine/Renderer/VertexArray.cpp b/Syndra/src/Engine/Renderer/VertexArray.cpp index 692edf7..dad3a14 100644 --- a/Syndra/src/Engine/Renderer/VertexArray.cpp +++ b/Syndra/src/Engine/Renderer/VertexArray.cpp @@ -1,6 +1,7 @@ #include "lpch.h" #include "Engine/Renderer/VertexArray.h" #include "Platform/OpenGL/OpenGLVertexArray.h" +#include "Platform/Vulkan/VulkanVertexArray.h" #include "Engine/Renderer/Renderer.h" namespace Syndra { @@ -10,10 +11,11 @@ namespace Syndra { { case RendererAPI::API::NONE: SN_CORE_ASSERT(false, "RendererAPI::NONE is not supported yet!"); return nullptr; case RendererAPI::API::OpenGL: return CreateRef(); + case RendererAPI::API::Vulkan: return CreateRef(); } SN_CORE_ASSERT(false, "Unknown API!"); return nullptr; } -} \ No newline at end of file +} diff --git a/Syndra/src/Platform/Vulkan/VulkanBuffer.cpp b/Syndra/src/Platform/Vulkan/VulkanBuffer.cpp new file mode 100644 index 0000000..9ff1d15 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanBuffer.cpp @@ -0,0 +1,17 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanBuffer.h" + +namespace Syndra { + + VulkanVertexBuffer::VulkanVertexBuffer(float* vertices, uint32_t size) + { + m_Data.assign(vertices, vertices + size / sizeof(float)); + } + + VulkanIndexBuffer::VulkanIndexBuffer(uint32_t* indices, uint32_t count) + : m_Count(count) + { + m_Data.assign(indices, indices + count); + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanBuffer.h b/Syndra/src/Platform/Vulkan/VulkanBuffer.h new file mode 100644 index 0000000..0e98458 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanBuffer.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Engine/Renderer/Buffer.h" + +namespace Syndra { + + class VulkanVertexBuffer : public VertexBuffer + { + public: + VulkanVertexBuffer(float* vertices, uint32_t size); + ~VulkanVertexBuffer() override = default; + + void Bind() const override {} + void UnBind() const override {} + + void SetLayout(const BufferLayout& layout) override { m_Layout = layout; } + const BufferLayout& GetLayout() const override { return m_Layout; } + private: + BufferLayout m_Layout; + std::vector m_Data; + }; + + class VulkanIndexBuffer : public IndexBuffer + { + public: + VulkanIndexBuffer(uint32_t* indices, uint32_t count); + ~VulkanIndexBuffer() override = default; + + void Bind() const override {} + void UnBind() const override {} + + uint32_t GetCount() const override { return m_Count; } + private: + uint32_t m_Count; + std::vector m_Data; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanContext.cpp b/Syndra/src/Platform/Vulkan/VulkanContext.cpp new file mode 100644 index 0000000..b8b540f --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanContext.cpp @@ -0,0 +1,505 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanContext.h" + +#define GLFW_INCLUDE_VULKAN +#include + +namespace Syndra { + + static std::vector GetRequiredInstanceExtensions() + { + uint32_t count = 0; + const char** extensions = glfwGetRequiredInstanceExtensions(&count); + return std::vector(extensions, extensions + count); + } + + VulkanContext* VulkanContext::s_Instance = nullptr; + + VulkanContext::VulkanContext(GLFWwindow* windowHandle) + : m_WindowHandle(windowHandle) + { + s_Instance = this; + } + + VulkanContext::~VulkanContext() + { + if (m_Device != VK_NULL_HANDLE) + vkDeviceWaitIdle(m_Device); + + for (auto fence : m_InFlightFences) + vkDestroyFence(m_Device, fence, nullptr); + for (auto semaphore : m_RenderFinishedSemaphores) + vkDestroySemaphore(m_Device, semaphore, nullptr); + for (auto semaphore : m_ImageAvailableSemaphores) + vkDestroySemaphore(m_Device, semaphore, nullptr); + + if (m_CommandPool != VK_NULL_HANDLE) + vkDestroyCommandPool(m_Device, m_CommandPool, nullptr); + + for (auto view : m_SwapchainImageViews) + vkDestroyImageView(m_Device, view, nullptr); + if (m_Swapchain != VK_NULL_HANDLE) + vkDestroySwapchainKHR(m_Device, m_Swapchain, nullptr); + if (m_Device != VK_NULL_HANDLE) + vkDestroyDevice(m_Device, nullptr); + if (m_Surface != VK_NULL_HANDLE) + vkDestroySurfaceKHR(m_Instance, m_Surface, nullptr); + if (m_Instance != VK_NULL_HANDLE) + vkDestroyInstance(m_Instance, nullptr); + } + + void VulkanContext::Init() + { + CreateInstance(); + CreateSurface(); + PickPhysicalDevice(); + CreateLogicalDevice(); + CreateSwapchain(); + CreateImageViews(); + CreateCommandPool(); + AllocateCommandBuffers(); + CreateSyncObjects(); + } + + void VulkanContext::SwapBuffers() + { + if (m_ActiveCommandBuffer == VK_NULL_HANDLE) + BeginFrame(); + EndFrame(); + } + + void VulkanContext::SetClearColor(const glm::vec4& color) + { + m_ClearColor = color; + } + + VulkanContext* VulkanContext::Get() + { + return s_Instance; + } + + void VulkanContext::PrepareFrame() + { + if (m_ActiveCommandBuffer == VK_NULL_HANDLE) + BeginFrame(); + } + + void VulkanContext::CreateInstance() + { + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Syndra"; + appInfo.apiVersion = VK_API_VERSION_1_3; + + auto extensions = GetRequiredInstanceExtensions(); + + VkInstanceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.enabledExtensionCount = static_cast(extensions.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + + VkResult result = vkCreateInstance(&createInfo, nullptr, &m_Instance); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create Vulkan instance"); + } + + void VulkanContext::CreateSurface() + { + VkResult result = glfwCreateWindowSurface(m_Instance, m_WindowHandle, nullptr, &m_Surface); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create Vulkan surface"); + } + + uint32_t VulkanContext::FindGraphicsQueueFamily(VkPhysicalDevice device) + { + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + + for (uint32_t i = 0; i < queueFamilyCount; ++i) + { + if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + return i; + } + + return 0; + } + + uint32_t VulkanContext::FindPresentQueueFamily(VkPhysicalDevice device) + { + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + + for (uint32_t i = 0; i < queueFamilyCount; ++i) + { + VkBool32 presentSupport = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, m_Surface, &presentSupport); + if (presentSupport) + return i; + } + + return 0; + } + + void VulkanContext::PickPhysicalDevice() + { + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(m_Instance, &deviceCount, nullptr); + SN_CORE_ASSERT(deviceCount > 0, "Failed to find GPUs with Vulkan support"); + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(m_Instance, &deviceCount, devices.data()); + + for (auto device : devices) + { + uint32_t graphicsQueueFamily = FindGraphicsQueueFamily(device); + uint32_t presentQueueFamily = FindPresentQueueFamily(device); + if (graphicsQueueFamily != UINT32_MAX && presentQueueFamily != UINT32_MAX) + { + m_PhysicalDevice = device; + return; + } + } + + SN_CORE_ASSERT(m_PhysicalDevice != VK_NULL_HANDLE, "Failed to select a Vulkan device"); + } + + void VulkanContext::CreateLogicalDevice() + { + float queuePriority = 1.0f; + uint32_t graphicsFamily = FindGraphicsQueueFamily(m_PhysicalDevice); + uint32_t presentFamily = FindPresentQueueFamily(m_PhysicalDevice); + + std::vector queueCreateInfos; + std::unordered_set uniqueFamilies{ graphicsFamily, presentFamily }; + for (uint32_t family : uniqueFamilies) + { + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = family; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + queueCreateInfos.push_back(queueCreateInfo); + } + + VkPhysicalDeviceSynchronization2Features sync2Features{}; + sync2Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; + sync2Features.synchronization2 = VK_TRUE; + + VkPhysicalDeviceDynamicRenderingFeatures dynamicRendering{}; + dynamicRendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; + dynamicRendering.dynamicRendering = VK_TRUE; + dynamicRendering.pNext = &sync2Features; + + VkPhysicalDeviceFeatures deviceFeatures{}; + + std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + + VkDeviceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + createInfo.pQueueCreateInfos = queueCreateInfos.data(); + createInfo.pEnabledFeatures = &deviceFeatures; + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); + createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + createInfo.pNext = &dynamicRendering; + + VkResult result = vkCreateDevice(m_PhysicalDevice, &createInfo, nullptr, &m_Device); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create logical device"); + + vkGetDeviceQueue(m_Device, graphicsFamily, 0, &m_GraphicsQueue); + vkGetDeviceQueue(m_Device, presentFamily, 0, &m_PresentQueue); + } + + void VulkanContext::CreateSwapchain() + { + VkSurfaceCapabilitiesKHR capabilities{}; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_PhysicalDevice, m_Surface, &capabilities); + + uint32_t formatCount = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhysicalDevice, m_Surface, &formatCount, nullptr); + std::vector formats(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(m_PhysicalDevice, m_Surface, &formatCount, formats.data()); + + VkSurfaceFormatKHR surfaceFormat = formats[0]; + for (const auto& format : formats) + { + if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + surfaceFormat = format; + break; + } + } + + uint32_t presentModeCount = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhysicalDevice, m_Surface, &presentModeCount, nullptr); + std::vector presentModes(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(m_PhysicalDevice, m_Surface, &presentModeCount, presentModes.data()); + + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + for (auto mode : presentModes) + { + if (mode == VK_PRESENT_MODE_MAILBOX_KHR) + { + presentMode = mode; + break; + } + } + + VkExtent2D extent = capabilities.currentExtent; + if (extent.width == UINT32_MAX) + { + extent.width = 1280; + extent.height = 720; + } + + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) + imageCount = capabilities.maxImageCount; + + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = m_Surface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + uint32_t queueFamilyIndices[] = { FindGraphicsQueueFamily(m_PhysicalDevice), FindPresentQueueFamily(m_PhysicalDevice) }; + if (queueFamilyIndices[0] != queueFamilyIndices[1]) + { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = 2; + createInfo.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + } + + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + VkResult result = vkCreateSwapchainKHR(m_Device, &createInfo, nullptr, &m_Swapchain); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create swapchain"); + + vkGetSwapchainImagesKHR(m_Device, m_Swapchain, &imageCount, nullptr); + m_SwapchainImages.resize(imageCount); + vkGetSwapchainImagesKHR(m_Device, m_Swapchain, &imageCount, m_SwapchainImages.data()); + + m_SwapchainFormat = surfaceFormat.format; + m_SwapchainExtent = extent; + } + + void VulkanContext::CreateImageViews() + { + m_SwapchainImageViews.resize(m_SwapchainImages.size()); + for (size_t i = 0; i < m_SwapchainImages.size(); ++i) + { + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = m_SwapchainImages[i]; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = m_SwapchainFormat; + viewInfo.components = { VK_COMPONENT_SWIZZLE_IDENTITY,VK_COMPONENT_SWIZZLE_IDENTITY,VK_COMPONENT_SWIZZLE_IDENTITY,VK_COMPONENT_SWIZZLE_IDENTITY }; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + VkResult result = vkCreateImageView(m_Device, &viewInfo, nullptr, &m_SwapchainImageViews[i]); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create swapchain image view"); + } + } + + void VulkanContext::CreateCommandPool() + { + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = FindGraphicsQueueFamily(m_PhysicalDevice); + + VkResult result = vkCreateCommandPool(m_Device, &poolInfo, nullptr, &m_CommandPool); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to create command pool"); + } + + void VulkanContext::AllocateCommandBuffers() + { + m_CommandBuffers.resize(m_SwapchainImages.size()); + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_CommandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = static_cast(m_CommandBuffers.size()); + + VkResult result = vkAllocateCommandBuffers(m_Device, &allocInfo, m_CommandBuffers.data()); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to allocate command buffers"); + } + + void VulkanContext::CreateSyncObjects() + { + m_ImageAvailableSemaphores.resize(m_SwapchainImages.size()); + m_RenderFinishedSemaphores.resize(m_SwapchainImages.size()); + m_InFlightFences.resize(m_SwapchainImages.size()); + + VkSemaphoreCreateInfo semaphoreInfo{}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fenceInfo{}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < m_SwapchainImages.size(); ++i) + { + SN_CORE_ASSERT(vkCreateSemaphore(m_Device, &semaphoreInfo, nullptr, &m_ImageAvailableSemaphores[i]) == VK_SUCCESS, "Failed to create semaphores"); + SN_CORE_ASSERT(vkCreateSemaphore(m_Device, &semaphoreInfo, nullptr, &m_RenderFinishedSemaphores[i]) == VK_SUCCESS, "Failed to create semaphores"); + SN_CORE_ASSERT(vkCreateFence(m_Device, &fenceInfo, nullptr, &m_InFlightFences[i]) == VK_SUCCESS, "Failed to create fences"); + } + } + + uint32_t VulkanContext::AcquireImage() + { + vkWaitForFences(m_Device, 1, &m_InFlightFences[m_CurrentFrame], VK_TRUE, UINT64_MAX); + + uint32_t imageIndex = 0; + VkResult result = vkAcquireNextImageKHR(m_Device, m_Swapchain, UINT64_MAX, m_ImageAvailableSemaphores[m_CurrentFrame], VK_NULL_HANDLE, &imageIndex); + SN_CORE_ASSERT(result == VK_SUCCESS, "Failed to acquire swapchain image"); + return imageIndex; + } + + void VulkanContext::TransitionToAttachment(VkCommandBuffer cmd, VkImage image) + { + VkImageMemoryBarrier2 barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + barrier.srcAccessMask = VK_ACCESS_2_NONE; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + barrier.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.image = image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + + VkDependencyInfo dependency{}; + dependency.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependency.imageMemoryBarrierCount = 1; + dependency.pImageMemoryBarriers = &barrier; + + vkCmdPipelineBarrier2(cmd, &dependency); + } + + void VulkanContext::TransitionToPresent(VkCommandBuffer cmd, VkImage image) + { + VkImageMemoryBarrier2 barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT; + barrier.dstAccessMask = VK_ACCESS_2_NONE; + barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barrier.image = image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + + VkDependencyInfo dependency{}; + dependency.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependency.imageMemoryBarrierCount = 1; + dependency.pImageMemoryBarriers = &barrier; + + vkCmdPipelineBarrier2(cmd, &dependency); + } + + void VulkanContext::BeginFrame() + { + m_ActiveImageIndex = AcquireImage(); + m_ActiveCommandBuffer = m_CommandBuffers[m_ActiveImageIndex]; + + vkResetFences(m_Device, 1, &m_InFlightFences[m_CurrentFrame]); + vkResetCommandBuffer(m_ActiveCommandBuffer, 0); + + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(m_ActiveCommandBuffer, &beginInfo); + + TransitionToAttachment(m_ActiveCommandBuffer, m_SwapchainImages[m_ActiveImageIndex]); + + VkRenderingAttachmentInfo colorAttachment{}; + colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + colorAttachment.imageView = m_SwapchainImageViews[m_ActiveImageIndex]; + colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.clearValue.color = { { m_ClearColor.r, m_ClearColor.g, m_ClearColor.b, m_ClearColor.a } }; + + VkRenderingInfo renderingInfo{}; + renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + renderingInfo.renderArea.offset = { 0,0 }; + renderingInfo.renderArea.extent = m_SwapchainExtent; + renderingInfo.layerCount = 1; + renderingInfo.colorAttachmentCount = 1; + renderingInfo.pColorAttachments = &colorAttachment; + + vkCmdBeginRendering(m_ActiveCommandBuffer, &renderingInfo); + } + + void VulkanContext::EndFrame() + { + if (m_ActiveCommandBuffer == VK_NULL_HANDLE) + return; + + vkCmdEndRendering(m_ActiveCommandBuffer); + TransitionToPresent(m_ActiveCommandBuffer, m_SwapchainImages[m_ActiveImageIndex]); + vkEndCommandBuffer(m_ActiveCommandBuffer); + + VkSemaphoreSubmitInfo waitSemaphore{}; + waitSemaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; + waitSemaphore.semaphore = m_ImageAvailableSemaphores[m_CurrentFrame]; + waitSemaphore.stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + + VkSemaphoreSubmitInfo signalSemaphore{}; + signalSemaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; + signalSemaphore.semaphore = m_RenderFinishedSemaphores[m_CurrentFrame]; + signalSemaphore.stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT; + + VkCommandBufferSubmitInfo commandBufferInfo{}; + commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + commandBufferInfo.commandBuffer = m_ActiveCommandBuffer; + + VkSubmitInfo2 submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; + submitInfo.waitSemaphoreInfoCount = 1; + submitInfo.pWaitSemaphoreInfos = &waitSemaphore; + submitInfo.commandBufferInfoCount = 1; + submitInfo.pCommandBufferInfos = &commandBufferInfo; + submitInfo.signalSemaphoreInfoCount = 1; + submitInfo.pSignalSemaphoreInfos = &signalSemaphore; + + SN_CORE_ASSERT(vkQueueSubmit2(m_GraphicsQueue, 1, &submitInfo, m_InFlightFences[m_CurrentFrame]) == VK_SUCCESS, "Failed to submit Vulkan command buffer"); + + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &m_RenderFinishedSemaphores[m_CurrentFrame]; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &m_Swapchain; + presentInfo.pImageIndices = &m_ActiveImageIndex; + vkQueuePresentKHR(m_PresentQueue, &presentInfo); + + m_CurrentFrame = (m_CurrentFrame + 1) % static_cast(m_SwapchainImages.size()); + m_ActiveCommandBuffer = VK_NULL_HANDLE; + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanContext.h b/Syndra/src/Platform/Vulkan/VulkanContext.h new file mode 100644 index 0000000..6e289ed --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanContext.h @@ -0,0 +1,81 @@ +#pragma once + +#include "Engine/Renderer/GraphicsContext.h" +#include +#include +#include + +struct GLFWwindow; + +namespace Syndra { + + class VulkanContext : public GraphicsContext + { + public: + explicit VulkanContext(GLFWwindow* windowHandle); + ~VulkanContext(); + + void Init() override; + void SwapBuffers() override; + + VkCommandBuffer GetActiveCommandBuffer() const { return m_ActiveCommandBuffer; } + void SetClearColor(const glm::vec4& color); + void PrepareFrame(); + VkDevice GetDevice() const { return m_Device; } + VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; } + VkQueue GetGraphicsQueue() const { return m_GraphicsQueue; } + VkFormat GetSwapchainFormat() const { return m_SwapchainFormat; } + VkExtent2D GetSwapchainExtent() const { return m_SwapchainExtent; } + + static VulkanContext* Get(); + + private: + void CreateInstance(); + void CreateSurface(); + void PickPhysicalDevice(); + void CreateLogicalDevice(); + void CreateSwapchain(); + void CreateImageViews(); + void CreateCommandPool(); + void AllocateCommandBuffers(); + void CreateSyncObjects(); + void BeginFrame(); + void EndFrame(); + uint32_t FindGraphicsQueueFamily(VkPhysicalDevice device); + uint32_t FindPresentQueueFamily(VkPhysicalDevice device); + uint32_t AcquireImage(); + void TransitionToAttachment(VkCommandBuffer cmd, VkImage image); + void TransitionToPresent(VkCommandBuffer cmd, VkImage image); + + private: + GLFWwindow* m_WindowHandle = nullptr; + + VkInstance m_Instance = VK_NULL_HANDLE; + VkSurfaceKHR m_Surface = VK_NULL_HANDLE; + VkPhysicalDevice m_PhysicalDevice = VK_NULL_HANDLE; + VkDevice m_Device = VK_NULL_HANDLE; + VkQueue m_GraphicsQueue = VK_NULL_HANDLE; + VkQueue m_PresentQueue = VK_NULL_HANDLE; + VkSwapchainKHR m_Swapchain = VK_NULL_HANDLE; + VkFormat m_SwapchainFormat{}; + VkExtent2D m_SwapchainExtent{}; + + std::vector m_SwapchainImages; + std::vector m_SwapchainImageViews; + + VkCommandPool m_CommandPool = VK_NULL_HANDLE; + std::vector m_CommandBuffers; + + std::vector m_ImageAvailableSemaphores; + std::vector m_RenderFinishedSemaphores; + std::vector m_InFlightFences; + + uint32_t m_CurrentFrame = 0; + uint32_t m_ActiveImageIndex = 0; + VkCommandBuffer m_ActiveCommandBuffer = VK_NULL_HANDLE; + glm::vec4 m_ClearColor{ 0.f }; + + static VulkanContext* s_Instance; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.cpp b/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.cpp new file mode 100644 index 0000000..78fadf0 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.cpp @@ -0,0 +1,31 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanFrameBuffer.h" + +namespace Syndra { + + VulkanFrameBuffer::VulkanFrameBuffer(const FramebufferSpecification& spec) + : m_Specification(spec) + { + } + + void VulkanFrameBuffer::Resize(uint32_t width, uint32_t height) + { + m_Specification.Width = width; + m_Specification.Height = height; + } + + int VulkanFrameBuffer::ReadPixel(uint32_t attachmentIndex, int x, int y) + { + (void)attachmentIndex; + (void)x; + (void)y; + return 0; + } + + void VulkanFrameBuffer::ClearAttachment(uint32_t attachmentIndex, int value) + { + (void)attachmentIndex; + (void)value; + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.h b/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.h new file mode 100644 index 0000000..7c9bfb6 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanFrameBuffer.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Engine/Renderer/FrameBuffer.h" + +namespace Syndra { + + class VulkanFrameBuffer : public FrameBuffer + { + public: + explicit VulkanFrameBuffer(const FramebufferSpecification& spec); + ~VulkanFrameBuffer() override = default; + + void Bind() override {} + void Unbind() override {} + + void Resize(uint32_t width, uint32_t height) override; + int ReadPixel(uint32_t attachmentIndex, int x, int y) override; + uint32_t GetRendererID() const override { return 0; } + void ClearAttachment(uint32_t attachmentIndex, int value) override; + uint32_t GetColorAttachmentRendererID(uint32_t index = 0) const override { (void)index; return 0; } + uint32_t GetDepthAttachmentRendererID() const override { return 0; } + void BindCubemapFace(uint32_t index) const override { (void)index; } + const FramebufferSpecification& GetSpecification() const override { return m_Specification; } + + private: + FramebufferSpecification m_Specification; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanRendererAPI.cpp b/Syndra/src/Platform/Vulkan/VulkanRendererAPI.cpp new file mode 100644 index 0000000..e9943d2 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanRendererAPI.cpp @@ -0,0 +1,97 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanRendererAPI.h" +#include "Platform/Vulkan/VulkanContext.h" +#include "Engine/Renderer/VertexArray.h" + +namespace Syndra { + + void VulkanRendererAPI::Init() + { + auto* context = VulkanContext::Get(); + SN_CORE_ASSERT(context, "Vulkan context not initialized"); + + VkPhysicalDeviceProperties props{}; + vkGetPhysicalDeviceProperties(context->GetPhysicalDevice(), &props); + SN_CORE_WARN("Driver: {0}", props.vendorID); + SN_CORE_WARN("Renderer: {0}", props.deviceName); + SN_CORE_WARN("API: {0}.{1}", VK_API_VERSION_MAJOR(props.apiVersion), VK_API_VERSION_MINOR(props.apiVersion)); + } + + void VulkanRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) + { + auto* context = VulkanContext::Get(); + if (!context) + return; + + context->PrepareFrame(); + VkViewport viewport{}; + viewport.x = static_cast(x); + viewport.y = static_cast(y); + viewport.width = static_cast(width); + viewport.height = static_cast(height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.offset = { static_cast(x), static_cast(y) }; + scissor.extent = { width, height }; + + VkCommandBuffer cmd = context->GetActiveCommandBuffer(); + if (cmd != VK_NULL_HANDLE) + { + vkCmdSetViewport(cmd, 0, 1, &viewport); + vkCmdSetScissor(cmd, 0, 1, &scissor); + } + } + + void VulkanRendererAPI::SetClearColor(const glm::vec4& color) + { + auto* context = VulkanContext::Get(); + if (context) + context->SetClearColor(color); + } + + void VulkanRendererAPI::Clear() + { + auto* context = VulkanContext::Get(); + if (!context) + return; + + context->PrepareFrame(); + } + + void VulkanRendererAPI::DrawIndexed(const Ref& vertexArray) + { + (void)vertexArray; + auto* context = VulkanContext::Get(); + if (!context) + return; + + context->PrepareFrame(); + // Full Vulkan pipeline integration will bind vertex and index buffers here. + // Dynamic rendering is active from Clear(), so defer rendering until pipeline work is added. + } + + void VulkanRendererAPI::SetState(RenderState stateID, bool on) + { + (void)stateID; + (void)on; + } + + std::string VulkanRendererAPI::GetRendererInfo() + { + auto* context = VulkanContext::Get(); + if (!context) + return "Vulkan context unavailable"; + + VkPhysicalDeviceProperties props{}; + vkGetPhysicalDeviceProperties(context->GetPhysicalDevice(), &props); + + std::string info{}; + info += "Vendor ID: " + std::to_string(props.vendorID) + "\n"; + info += "Renderer: " + std::string(props.deviceName) + "\n"; + info += "API Version: " + std::to_string(VK_API_VERSION_MAJOR(props.apiVersion)) + "." + std::to_string(VK_API_VERSION_MINOR(props.apiVersion)); + return info; + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanRendererAPI.h b/Syndra/src/Platform/Vulkan/VulkanRendererAPI.h new file mode 100644 index 0000000..59a22e9 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanRendererAPI.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Engine/Renderer/RendererAPI.h" + +namespace Syndra { + + class VulkanRendererAPI : public RendererAPI + { + public: + void Init() override; + void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; + void SetClearColor(const glm::vec4& color) override; + void Clear() override; + void DrawIndexed(const Ref& vertexArray) override; + void SetState(RenderState stateID, bool on) override; + std::string GetRendererInfo() override; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanShader.cpp b/Syndra/src/Platform/Vulkan/VulkanShader.cpp new file mode 100644 index 0000000..d2f5284 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanShader.cpp @@ -0,0 +1,21 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanShader.h" + +namespace Syndra { + + VulkanShader::VulkanShader(const std::string& path) + { + auto lastSlash = path.find_last_of("/\\"); + auto lastDot = path.rfind('.'); + lastDot = lastDot == std::string::npos ? path.size() : lastDot; + m_Name = path.substr(lastSlash + 1, lastDot - lastSlash - 1); + } + + VulkanShader::VulkanShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc) + { + (void)vertexSrc; + (void)fragmentSrc; + m_Name = name; + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanShader.h b/Syndra/src/Platform/Vulkan/VulkanShader.h new file mode 100644 index 0000000..3941390 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanShader.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Engine/Renderer/Shader.h" + +namespace Syndra { + + class VulkanShader : public Shader + { + public: + explicit VulkanShader(const std::string& path); + VulkanShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc); + ~VulkanShader() override = default; + + void Bind() const override {} + void UnBind() const override {} + + void SetInt(const std::string& name, int value) override { (void)name; (void)value; } + void SetFloat(const std::string& name, float value) override { (void)name; (void)value; } + void SetFloat3(const std::string& name, const glm::vec3& value) override { (void)name; (void)value; } + void SetFloat4(const std::string& name, const glm::vec4& value) override { (void)name; (void)value; } + void SetMat4(const std::string& name, const glm::mat4& value) override { (void)name; (void)value; } + + const std::string& GetName() const override { return m_Name; } + private: + std::string m_Name; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanTexture2D.cpp b/Syndra/src/Platform/Vulkan/VulkanTexture2D.cpp new file mode 100644 index 0000000..6b22fe3 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanTexture2D.cpp @@ -0,0 +1,42 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanTexture2D.h" + +namespace Syndra { + + VulkanTexture2D::VulkanTexture2D(uint32_t width, uint32_t height) + : m_Width(width), m_Height(height) + { + m_Pixels.resize(static_cast(width) * height * 4); + } + + VulkanTexture2D::VulkanTexture2D(const std::string& path, bool sRGB, bool HDR) + { + (void)path; + (void)sRGB; + (void)HDR; + m_Width = 1; + m_Height = 1; + m_Pixels.resize(4, 255); + } + + VulkanTexture2D::VulkanTexture2D(uint32_t width, uint32_t height, const unsigned char* data, bool sRGB) + : m_Width(width), m_Height(height) + { + (void)sRGB; + m_Pixels.assign(data, data + (static_cast(width) * height * 4)); + } + + VulkanTexture1D::VulkanTexture1D(uint32_t size) + : m_Size(size) + { + m_Data.resize(size); + } + + VulkanTexture1D::VulkanTexture1D(uint32_t size, void* data) + : m_Size(size) + { + auto* bytes = static_cast(data); + m_Data.assign(bytes, bytes + size); + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanTexture2D.h b/Syndra/src/Platform/Vulkan/VulkanTexture2D.h new file mode 100644 index 0000000..edc9330 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanTexture2D.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Engine/Renderer/Texture.h" + +namespace Syndra { + + class VulkanTexture2D : public Texture2D + { + public: + VulkanTexture2D(uint32_t width, uint32_t height); + VulkanTexture2D(const std::string& path, bool sRGB, bool HDR); + VulkanTexture2D(uint32_t width, uint32_t height, const unsigned char* data, bool sRGB); + ~VulkanTexture2D() override = default; + + uint32_t GetWidth() const override { return m_Width; } + uint32_t GetHeight() const override { return m_Height; } + + void SetData(void* data, uint32_t size) override { (void)data; (void)size; } + void Bind(uint32_t slot = 0) const override { (void)slot; } + + private: + uint32_t m_Width; + uint32_t m_Height; + std::vector m_Pixels; + }; + + class VulkanTexture1D : public Texture1D + { + public: + VulkanTexture1D(uint32_t size); + VulkanTexture1D(uint32_t size, void* data); + ~VulkanTexture1D() override = default; + + uint32_t GetSize() override { return m_Size; } + + void SetData(void* data, uint32_t size) override { (void)data; (void)size; } + void Bind(uint32_t slot = 0) const override { (void)slot; } + private: + uint32_t m_Size; + std::vector m_Data; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.cpp b/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.cpp new file mode 100644 index 0000000..5b68fba --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.cpp @@ -0,0 +1,21 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanUniformBuffer.h" +#include + +namespace Syndra { + + VulkanUniformBuffer::VulkanUniformBuffer(uint32_t size, uint32_t binding) + : m_Data(size), m_Binding(binding) + { + (void)m_Binding; + } + + void VulkanUniformBuffer::SetData(const void* data, uint32_t size, uint32_t offset) + { + if (offset + size > m_Data.size()) + m_Data.resize(offset + size); + + std::memcpy(m_Data.data() + offset, data, size); + } + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.h b/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.h new file mode 100644 index 0000000..e0c02dd --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanUniformBuffer.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Engine/Renderer/UniformBuffer.h" + +namespace Syndra { + + class VulkanUniformBuffer : public UniformBuffer + { + public: + VulkanUniformBuffer(uint32_t size, uint32_t binding); + ~VulkanUniformBuffer() override = default; + + void SetData(const void* data, uint32_t size, uint32_t offset = 0) override; + private: + std::vector m_Data; + uint32_t m_Binding = 0; + }; + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanVertexArray.cpp b/Syndra/src/Platform/Vulkan/VulkanVertexArray.cpp new file mode 100644 index 0000000..4cda0e9 --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanVertexArray.cpp @@ -0,0 +1,6 @@ +#include "lpch.h" +#include "Platform/Vulkan/VulkanVertexArray.h" + +namespace Syndra { + +} diff --git a/Syndra/src/Platform/Vulkan/VulkanVertexArray.h b/Syndra/src/Platform/Vulkan/VulkanVertexArray.h new file mode 100644 index 0000000..d5464ec --- /dev/null +++ b/Syndra/src/Platform/Vulkan/VulkanVertexArray.h @@ -0,0 +1,27 @@ +#pragma once + +#include "Engine/Renderer/VertexArray.h" + +namespace Syndra { + + class VulkanVertexArray : public VertexArray + { + public: + VulkanVertexArray() = default; + ~VulkanVertexArray() override = default; + + void Bind() const override {} + void UnBind() const override {} + + void AddVertexBuffer(const Ref& vertexBuffer) override { m_VertexBuffers.push_back(vertexBuffer); } + void SetIndexBuffer(const Ref& indexBuffer) override { m_IndexBuffer = indexBuffer; } + + const std::vector>& GetVertexBuffers() const override { return m_VertexBuffers; } + const Ref& GetIndexBuffer() const override { return m_IndexBuffer; } + + private: + std::vector> m_VertexBuffers; + Ref m_IndexBuffer; + }; + +} diff --git a/Syndra/src/Platform/Windows/WindowsWindow.cpp b/Syndra/src/Platform/Windows/WindowsWindow.cpp index f655e7b..52b604c 100644 --- a/Syndra/src/Platform/Windows/WindowsWindow.cpp +++ b/Syndra/src/Platform/Windows/WindowsWindow.cpp @@ -8,6 +8,8 @@ #include "Engine/Core/Instrument.h" #include "Platform/OpenGL/OpenGLContext.h" +#include "Platform/Vulkan/VulkanContext.h" +#include "Engine/Renderer/Renderer.h" #include "stb_image.h" namespace Syndra { @@ -40,9 +42,16 @@ namespace Syndra { m_Data.Title = props.Title; m_Data.Width = props.Width; m_Data.Height = props.Height; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + if (Renderer::GetAPI() == RendererAPI::API::OpenGL) + { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + } + else + { + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + } //glfwWindowHint(GLFW_SAMPLES,8); SN_CORE_INFO("Creating window {0} ({1}, {2})", props.Title, props.Width, props.Height); @@ -71,7 +80,10 @@ namespace Syndra { glfwSetWindowIcon(m_Window, 1, images); stbi_image_free(images[0].pixels); - m_Context = new OpenGLContext(m_Window); + if (Renderer::GetAPI() == RendererAPI::API::Vulkan) + m_Context = new VulkanContext(m_Window); + else + m_Context = new OpenGLContext(m_Window); m_Context->Init(); //SN_CORE_INFO(m_Window); @@ -196,10 +208,13 @@ namespace Syndra { { //SN_PROFILE_FUNCTION(); - if (enabled) - glfwSwapInterval(1); - else - glfwSwapInterval(0); + if (Renderer::GetAPI() == RendererAPI::API::OpenGL) + { + if (enabled) + glfwSwapInterval(1); + else + glfwSwapInterval(0); + } m_Data.VSync = enabled; } @@ -214,4 +229,4 @@ namespace Syndra { glfwSetWindowTitle(m_Window, title.c_str()); } -} \ No newline at end of file +} diff --git a/premake5.lua b/premake5.lua index 01fc2e9..01fdaf3 100644 --- a/premake5.lua +++ b/premake5.lua @@ -105,7 +105,8 @@ project "Syndra" "Glad", "imgui", "yaml-cpp", - "opengl32.lib" + "opengl32.lib", + "%{Library.Vulkan}" } filter "files:Syndra/vendor/ImGuizmo/**.cpp" @@ -199,4 +200,4 @@ project "Sandbox" filter "configurations:Dist" defines "SN_DIST" - optimize "on" \ No newline at end of file + optimize "on"