diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..572961a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,13 @@ +name: ✅ CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + schedule: + - cron: "0 12 * * 0" + +jobs: + secrets: inherit diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9ed074f..4c8e012 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,17 +1,15 @@ +# Breaking change was removing the bit timing sections from hal::can::settings, +# now it is just baud_rate. name: 🚀 Deploy Version on: workflow_dispatch: jobs: - deploy: - if: startsWith(github.ref, 'refs/tags/') - uses: engine3d-dev/ci/.github/workflows/deploy.yml@1.x.y + engine3d: + uses: engine3d-dev/ci/.github/workflows/deploy.yml@main with: - compiler: gcc - version: ${{ github.ref_name }} + # version: ${{ github.ref_name }} arch: x86_64 - compiler_version: 12.3 - compiler_package: "" os: Linux - secrets: inherit \ No newline at end of file + secrets: inherit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4de5f65 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "engine3d/Core/backend/third_party/JolyPhysics"] + path = engine3d/Core/backend/third_party/JolyPhysics + url = https://github.com/engine3d-dev/JoltPhysics +[submodule "engine3d/Core/backend/third_party/imgui"] + path = engine3d/Core/backend/third_party/imgui + url = https://github.com/SpinnerX/imgui +[submodule "engine3d/Core/backend/third_party/ImGuizmo"] + path = engine3d/Core/backend/third_party/ImGuizmo + url = https://github.com/SpinnerX/ImGuizmo \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a0dd54..924518e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,58 +3,24 @@ project(engine3d C CXX) set(CMAKE_CXX_STANDARD 23) -# Setting the makefile location in chocolatey -# set(CMAKE_MAKE_PROGRAM "${env:ChocolateyInstall}") -# set(CMAKE_GENERATOR "Unix Makefiles") -# message("generator is set to ${CMAKE_GENERATOR}/make.exe") -# set(CMAKE_MAKE_PROGRAM $ENV{ChocolateyInstall}/make.exe) -# message("Testing message from engine3d/CMakeLists.txt!!!") -# message("Choco make directory ===============>>> ${CMAKE_MAKE_PROGRAM}") - set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") # works (in creating the compile_commands.json file) find_package(OpenGL REQUIRED) find_package(glfw3 REQUIRED) find_package(Vulkan REQUIRED) -find_package(VulkanHeaders REQUIRED) find_package(glm REQUIRED) find_package(fmt REQUIRED) find_package(spdlog REQUIRED) find_package(yaml-cpp REQUIRED) +find_package(imguidocking REQUIRED) find_package(box2d REQUIRED) -# find_package(SPIRV-Tools REQUIRED) -# add_subdirectory(engine3d/Core/backend/third_party/JoltPhysics) - -include(FetchContent) - -# Include Jolt (3D Physics framework) -FetchContent_Declare( - JoltPhysics - GIT_REPOSITORY "https://github.com/engine3d-dev/JoltPhysics" - SOURCE_SUBDIR "build" -) - -FetchContent_MakeAvailable(JoltPhysics) - -# find_package(shaderc REQUIRED) -# find_package(joltphysics REQUIRED) -# For some reason draco is having some errors with ftell in one of it's files -# Draco is a dependency for using assimp +find_package(joltphysics REQUIRED) # find_package(assimp REQUIRED) -# find_package(shaderc REQUIRED) add_subdirectory(src) -add_subdirectory(Editor) -add_subdirectory(Testbed) - -# This will run the build doing -j which is building at full capacity. -# TODO - Should probably have this be disabled by default and have this be a flag set through conan. -# add_custom_target(my_parallel_build -# COMMAND ${CMAKE_COMMAND} --build -j -# WORKING_DIRECTORY ${CMAKE_BINARY_DIR} -# COMMENT "My parallel build with 5 cores") +# add_subdirectory(Editor) -# Copy to source directory +# Copy to compile_commands.json for .clangd add_custom_target( copy-compile-commands ALL DEPENDS @@ -90,26 +56,43 @@ add_custom_command( # Usage - used to suppress that lld-link error and use the defaulted linked .library if(MSVC) target_compile_options(${PROJECT_NAME} PUBLIC "/Z1" "/NOD") +# else() +# target_compile_options(${PROJECT_NAME} PUBLIC "-fsanitize=address") endif(MSVC) # target_include_directory is setting some private settings for differentiating what internal includes are privates and what should be includes should be exposed to the application-dev target_include_directories(${PROJECT_NAME} PRIVATE engine3d/ engine3d/Core) -message("PROJECT SOURCE DIR ====>>> ${CMAKE_SOURCE_DIR}") +<<<<<<< HEAD +======= +# message("PROJECT SOURCE DIR ====>>> ${CMAKE_SOURCE_DIR}") +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f target_include_directories(${PROJECT_NAME} PUBLIC ${JoltPhysics_SOURCE_DIR} ${GLM_INCLUDE_DIR} ./engine3d) target_link_libraries( ${PROJECT_NAME} - PUBLIC + PRIVATE glfw ${OPENGL_LIBRARIES} Vulkan::Vulkan - vulkan-headers::vulkan-headers +<<<<<<< HEAD +======= + # vulkan-headers::vulkan-headers +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f glm::glm fmt::fmt spdlog::spdlog yaml-cpp::yaml-cpp +<<<<<<< HEAD + imguidocking::imguidocking box2d::box2d - Jolt + Jolt::Jolt +======= + # box2d::box2d + # Jolt + imguidocking::imguidocking + Jolt::Jolt + # shaderc::shaderc +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f ) install(TARGETS ${PROJECT_NAME}) diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 8d12f21..f89ecc6 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -1,31 +1,31 @@ cmake_minimum_required(VERSION 3.15) project(Editor CXX) -include_directories( - ../ -) - set( all_src + Editor/Editor.h Editor/Editor.cpp Editor/EngineLayer.cpp Editor/UILayer.cpp - platforms/main.cpp - platforms/win32.cpp ) +find_package(spdlog REQUIRED) +find_package(glm REQUIRED) +find_package(yaml-cpp REQUIRED) +find_package(Vulkan REQUIRED) +find_package(imguidocking REQUIRED) +find_package(engine3d REQUIRED) add_executable(${PROJECT_NAME} ${all_src}) -# target_link_libraries(${PROJECT_NAME} engine3d) +target_include_directories(${PROJECT_NAME} PRIVATE ../) + target_link_libraries( ${PROJECT_NAME} - engine3d - glfw - glm::glm - fmt::fmt spdlog::spdlog + glm::glm yaml-cpp::yaml-cpp - box2d::box2d - # joltphysics::joltphysics + Vulkan::Vulkan + imguidocking::imguidocking + engine3d::engine3d ) \ No newline at end of file diff --git a/Editor/Editor/Editor.cpp b/Editor/Editor/Editor.cpp index 12e52c0..0ce3c13 100644 --- a/Editor/Editor/Editor.cpp +++ b/Editor/Editor/Editor.cpp @@ -1,87 +1,71 @@ #include "Editor.h" -#include "EngineLayer.h" -#include "UILayer.h" +#include +#include "engine3d/Core/EngineLogger.h" #include "engine3d/Core/Renderer/Renderer.h" #include -#include +#include namespace engine3d{ - EditorApplication::EditorApplication(){ - InitiateEditor(); + EditorApplication::EditorApplication(const std::string& p_DebugName) : ApplicationInstance(p_DebugName) { +<<<<<<< HEAD + Renderer::Initialize(); + Renderer::SetBackgroundColor({1.0f, 0.0f, 0.0f, 0.0f}); } - EditorApplication::~EditorApplication(){ - ShutdownEditor(); - } + EditorApplication::~EditorApplication() {} - void EditorApplication::InitiateEditor(){ - //! @note Initially we will have our actual rendering and everything engine-related in EngineLayer - //! @note UILayer is where all of the UI-related stuff are done. - //! @note UILayer for right now is used for initiating any imgui related configurations. - m_Layers[0] = new EngineLayer(); - m_Layers[0]->OnAttach(); - m_Layers[1] = new UILayer(); - m_Layers[1]->OnAttach(); + void EditorApplication::UpdateThisApplicationInstance(){ - Renderer::Initialize(); - - //! @note Setting our color to being light blue - Renderer::SetBackgroundColor({0.0f, 0.5f, 0.5f, 0.f}); - // Renderer::SetBackgroundColor({1.0f, 0.0f, 0.0f, 1.0f}); - - // m_CmdBuffer = vk::VulkanCommandBuffer(vk::VulkanSwapchain::GetImagesSize()); - // m_CmdBuffer.RecordCommandBuffers(); - - //! @param index, zero - indicates getting first data in queue at index 0 (zero) - //! @note TODO -- for cmd buffers/queues, shader modules, and render passes. Figuring out what parameters are important that users should specify when creating this instance - //! @note This is because as it stands the API requires for instancing the object before initializing it, but should just utilize the constructor to cleanup the API for initiating our object's lifetimes. - // m_CmdQueue = vk::VulkanCommandQueue(0); - // m_RenderPass.InitializeRenderPass(); - // m_RenderPass.InitializeFramebuffers(); - // m_TriangleShaderVertModule = vk::VulkanShaderModule("Resources/shaders/TriangleShader/triangle.vert.spirv"); - // m_TriangleShaderFragModule = vk::VulkanShaderModule("Resources/shaders/TriangleShader/triangle.frag.spirv"); - // engine3d::UILayer::InitializeUI(m_CmdQueue.GetVkQueueInstance()); - - // m_ShaderPipeline = vk::VulkanShaderCompiler(m_TriangleShaderVertModule.GetVkShaderModuleInstance(), m_TriangleShaderFragModule.GetVkShaderModuleInstance(), m_RenderPass.GetRenderPassInstnace()); - + //! @note Just testing to see if application still closes cleanly. + // if(InputPoll::IsKeyPressed(ENGINE_KEY_ESCAPE)){ + // exit(0); + // } + + //! @note This function will render our primitives + //! @note TODO -- Flush should only happens when our scene is given everything that lives within this scene (ref to lifetimes) + /* Renderer::FlushScene(); */ + + Renderer::Presentation(); + // ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + // ImGui::End(); } - void EditorApplication::ShutdownEditor(){ - // m_Pipeline.CleanupPipeline(); - // m_VulkDevice.CleanupDevice(); + ApplicationInstance* InitializeApplication(){ + return new EditorApplication(); } - void EditorApplication::RunEditor(){ +======= + /* Renderer::Initialize(); */ + /* Renderer::SetBackgroundColor({0.0f, 0.5f, 0.5f, 0.f}); */ + Renderer::SetBackgroundColor({1.0f, 0.0f, 0.0f, 0.0f}); - while(!glfwWindowShouldClose(vk::VulkanPipeline::GetCurrentWindow())){ - m_LastFrameTime = (float)glfwGetTime(); - Timerstep ts = m_LastFrameTime; + ConsoleLogInfo("Initializing Current Application Name === {}!!!", ApplicationInstance::CurrentApplicationName()); + } - for(const auto& layer : m_Layers){ - layer->OnUpdate(ts); - } + EditorApplication::~EditorApplication() {} - // Clearing screen - // uint32_t idx = m_CmdQueue.AcquireNextImage(); - // m_CmdQueue.WaitIdleFence(); - // m_CmdQueue.SubmitAsync(m_CmdBuffer[idx]); - // // m_CmdQueue.WaitIdle(); - // m_CmdQueue.WaitIdleFence(); - // m_CmdQueue.Presentation(idx); - Renderer::FlushScene(); + void EditorApplication::UpdateThisApplicationInstance(){ + + //! @note Just testing to see if application still closes cleanly. + // if(InputPoll::IsKeyPressed(ENGINE_KEY_ESCAPE)){ + // exit(0); + // } + + //! @note This function will render our primitives + //! @note TODO -- Flush should only happens when our scene is given everything that lives within this scene (ref to lifetimes) + /* Renderer::FlushScene(); */ + + Renderer::Presentation(); + // ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + // ImGui::End(); + } - // m_RenderPass.BeginPass(idx, m_CmdBuffer[idx], VK_SUBPASS_CONTENTS_INLINE, m_ShaderPipeline.GetShaderPipeline()); - // vkCmdBindPipeline(m_CmdBuffer[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, m_ShaderPipeline.GetShaderPipeline()); - // vkCmdDraw(m_CmdBuffer[idx], 3, 1, 0, 0); - // m_RenderPass.EndPass(m_CmdBuffer[idx]); + ApplicationInstance* InitializeApplication(){ + return new EditorApplication(); + } - for(const auto& layer : m_Layers){ - layer->OnUIRender(); - } +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f - glfwPollEvents(); - } - } -}; \ No newline at end of file +}; diff --git a/Editor/Editor/Editor.h b/Editor/Editor/Editor.h index 876913d..b221cf2 100644 --- a/Editor/Editor/Editor.h +++ b/Editor/Editor/Editor.h @@ -1,30 +1,23 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace engine3d{ //! @note Our actual editor application - class EditorApplication{ + //! @note TODO -- Having a cenrtal application that will be used across both editor and the game(being developed) + //! @note So when they're packaged, they can be shipped under one application excluding editor stuff and only things relevant to the game. + class EditorApplication : public ApplicationInstance{ public: - EditorApplication(); - ~EditorApplication(); - - void RunEditor(); + EditorApplication(const std::string& debugName = "Engine3D Editor"); + virtual ~EditorApplication(); private: - void InitiateEditor(); - void ShutdownEditor(); + //! @note TODO -- Probably have a cleanup handler for this + //! @note Such as WorldCleanup() or some API to make sure we can cleanly deallocate and delete things... + // void ShutdownEditor(); + void UpdateThisApplicationInstance() override; private: //! @note Editor application, Engine, UI Layer. - std::array m_Layers; float m_LastFrameTime = 0.0f; }; }; \ No newline at end of file diff --git a/Editor/Editor/EngineLayer.cpp b/Editor/Editor/EngineLayer.cpp index c381035..bffb8fe 100644 --- a/Editor/Editor/EngineLayer.cpp +++ b/Editor/Editor/EngineLayer.cpp @@ -1,6 +1,7 @@ #include "EngineLayer.h" -#include "engine3d/Core/EngineLogger.h" -#include "engine3d/Core/Event/InputPoll.h" +#include +#include +#include namespace engine3d{ EngineLayer::EngineLayer() : Layer("EngineLayer") {} @@ -16,13 +17,14 @@ namespace engine3d{ void EngineLayer::UpdateFrame(float ts){ // ConsoleLogInfo("EngineLayer::UpdateFrame(float) function called"); if(InputPoll::IsKeyPressed(ENGINE_KEY_ESCAPE)){ + ConsoleLogError("IsKeyPressed pressed!"); exit(0); } } - void EngineLayer::UpdateEvent(Event& event){ - // ConsoleLogInfo("EngineLayer::UpdateEvent(Event&) function called"); - } + // void EngineLayer::UpdateEvent(Event& event){ + // // ConsoleLogInfo("EngineLayer::UpdateEvent(Event&) function called"); + // } void EngineLayer::UpdateUI(){} diff --git a/Editor/Editor/EngineLayer.h b/Editor/Editor/EngineLayer.h index f87230e..6b41a35 100644 --- a/Editor/Editor/EngineLayer.h +++ b/Editor/Editor/EngineLayer.h @@ -14,7 +14,7 @@ namespace engine3d{ void BeginPlay() override; void EndPlay() override; void UpdateFrame(float ts) override; - void UpdateEvent(Event& event) override; + // void UpdateEvent(Event& event) override; void UpdateUI() override; }; }; \ No newline at end of file diff --git a/Editor/Editor/UILayer.cpp b/Editor/Editor/UILayer.cpp index 90d8e43..a2a8b83 100644 --- a/Editor/Editor/UILayer.cpp +++ b/Editor/Editor/UILayer.cpp @@ -4,15 +4,12 @@ // #include "engine3d/Core/backend/Vulkan/VulkanSwapchain.h" #include #include -#include -#include -#include namespace engine3d{ UILayer::UILayer() : Layer("UILayer") { } - void UILayer::InitializeUI(VkQueue queue){ + void UILayer::InitializeUI(){ // IMGUI_CHECKVERSION(); // ImGui::CreateContext(); // ImGuiIO& io = ImGui::GetIO(); (void)io; @@ -37,7 +34,7 @@ namespace engine3d{ // init_info.Instance = vk::VulkanPipeline::GetVkInstance(); // init_info.PhysicalDevice = vk::VulkanDevice::GetVkPhysicalDeviceInstance(); // init_info.Device = vk::VulkanDevice::GetVkLogicalDeviceInstance(); - // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamily(); + // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); // // init_info.Queue = g_Queue; // init_info.Queue = queue, // // init_info.PipelineCache = g_PipelineCache; @@ -87,7 +84,7 @@ namespace engine3d{ // init_info.Instance = vk::VulkanPipeline::GetVkInstance(); // init_info.PhysicalDevice = vk::VulkanDevice::GetVkPhysicalDeviceInstance(); // init_info.Device = vk::VulkanDevice::GetVkLogicalDeviceInstance(); - // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamily(); + // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); // // init_info.Queue = g_Queue; // init_info.Queue = nullptr, // // init_info.PipelineCache = g_PipelineCache; @@ -134,9 +131,9 @@ namespace engine3d{ // ConsoleLogInfo("UILayer::UpdateFrame(float) function called in class {}", Layer::GetLayerString()); } - void UILayer::UpdateEvent(Event& event){ - // ConsoleLogInfo("UILayer::UpdateEvent(Event&) function called in class {}", Layer::GetLayerString()); - } + // void UILayer::UpdateEvent(Event& event){ + // // ConsoleLogInfo("UILayer::UpdateEvent(Event&) function called in class {}", Layer::GetLayerString()); + // } void UILayer::UpdateUI(){ // ImGui::Begin("Settings"); diff --git a/Editor/Editor/UILayer.h b/Editor/Editor/UILayer.h index bb419f4..6e7b01e 100644 --- a/Editor/Editor/UILayer.h +++ b/Editor/Editor/UILayer.h @@ -2,21 +2,20 @@ #include #include -#include namespace engine3d{ class UILayer : public engine3d::Layer{ public: UILayer(); - static void InitializeUI(VkQueue queue); + static void InitializeUI(); std::string GetName() const; protected: void BeginPlay() override; void EndPlay() override; void UpdateFrame(float ts) override; - void UpdateEvent(Event& event) override; + // void UpdateEvent(Event& event) override; void UpdateUI() override; }; }; \ No newline at end of file diff --git a/Editor/conanfile.py b/Editor/conanfile.py new file mode 100644 index 0000000..29b28c0 --- /dev/null +++ b/Editor/conanfile.py @@ -0,0 +1,57 @@ +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.scm import Git +from conan.tools.files import copy +import os + +class Editor(ConanFile): + name = "editor" + version = "1.0" + + # Binary configuration + settings = "os", "compiler", "build_type", "arch" + exports_sources = "CMakeLists.txt", "Editor/*" + + def requirements(self): +<<<<<<< HEAD +======= + # self.requires("getopt-for-visual-studio/20200201") +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + self.requires("imguidocking/1.0") + self.requires("engine3d/1.0") + + def generate(self): + cmake = CMakeDeps(self) + cmake.generate() + tc = CMakeToolchain(self, generator="Unix Makefiles") + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def layout(self): +<<<<<<< HEAD + cmake_layout(self) +======= + cmake_layout(self) + + # def package(self): + # copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) + # copy(self, pattern="*.h", src=os.path.join(self.source_folder, "./Editor/"), dst=os.path.join(self.package_folder, "Editor")) + # copy(self, pattern="*.cpp", src=os.path.join(self.source_folder, "./Editor/"), dst=os.path.join(self.package_folder, "Editor")) + # copy(self, pattern="*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) + # copy(self, pattern="*.so", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) + # copy(self, pattern="*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) + # copy(self, pattern="*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"), keep_path=False) + # copy(self, pattern="*.dylib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False) + # cmake = CMake(self) + # cmake.install() + + # def package_info(self): + # self.cpp_info.set_property("cmake_target_name", "engine3d::engine3d") + # self.cpp_info.libs = ["engine3d"] + # self.cpp_info.includedirs = ['./', './engine3d'] # Ordered list of include paths + +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f diff --git a/Editor/imgui.ini b/Editor/imgui.ini new file mode 100644 index 0000000..315c1a1 --- /dev/null +++ b/Editor/imgui.ini @@ -0,0 +1,12 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Hello, world!] +Pos=60,60 +Size=32,35 +Collapsed=0 + +[Docking][Data] + diff --git a/Editor/platforms/main.cpp b/Editor/platforms/main.cpp deleted file mode 100644 index be0ea1a..0000000 --- a/Editor/platforms/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name platforms entry points - * @note Platform entry points target the specific platforms we will want to support - * @note Windows, Mac, Linux -*/ - -//! @note Main will be called based on our current platform -extern int Main(int argc, char** argv); - - -int main(int argc, char** argv){ - return Main(argc, argv); -} \ No newline at end of file diff --git a/Editor/platforms/win32.cpp b/Editor/platforms/win32.cpp deleted file mode 100644 index 5fb3b24..0000000 --- a/Editor/platforms/win32.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - -extern void Engine3DInitializeCore(); - -/** - * @param Question - * @note Platforms are a way that we can target the different platforms developers may want to develop games for. -*/ -int Main(int argc, char** argv){ - Engine3DInitializeCore(); - ConsoleLogInfo("Initiating Win32 supported platform"); - engine3d::EditorApplication* editor = new engine3d::EditorApplication(); - editor->RunEditor(); - return 0; -} \ No newline at end of file diff --git a/Resources/shaders/TriangleShader/TestTriangle.glsl b/Resources/shaders/TriangleShader/TestTriangle.glsl new file mode 100644 index 0000000..a25d4a1 --- /dev/null +++ b/Resources/shaders/TriangleShader/TestTriangle.glsl @@ -0,0 +1,42 @@ +//we will be using glsl version 4.5 syntax +#vertex +#version 450 + +layout (location = 0) out vec3 outColor; + +void main() +{ + //const array of positions for the triangle + const vec3 positions[3] = vec3[3]( + vec3(1.f,1.f, 0.0f), + vec3(-1.f,1.f, 0.0f), + vec3(0.f,-1.f, 0.0f) + ); + + const vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) + ); + + //output the position of each vertex + gl_Position = vec4(positions[gl_VertexIndex], 1.0f); + outColor = colors[gl_VertexIndex]; +} + +#fragment +//glsl version 4.5 +#version 450 + +//shader input +layout (location = 0) in vec3 inColor; + +// output write] +layout(location = 0) out vec4 outFragColor; + +void main() +{ + //return red + // outFragColor = vec4(1.f,0.f,0.f,1.0f); + outFragColor = vec4(inColor, 1.0); +} diff --git a/Testbed/Application.cpp b/Testbed/Application.cpp new file mode 100644 index 0000000..3d03bed --- /dev/null +++ b/Testbed/Application.cpp @@ -0,0 +1,13 @@ +#include "Application.h" +#include + +namespace engine3d{ + TestbedApplication::TestbedApplication(const std::string& p_DebugName){ + Renderer::Initialize(); + Renderer::SetBackgroundColor({1.0f, 0.0f, 0.0f, 0.0f}); + } + + void TestbedApplication::UpdateThisApplicationInstance(){ + Renderer::Presentation(); + } +}; \ No newline at end of file diff --git a/Testbed/Application.h b/Testbed/Application.h new file mode 100644 index 0000000..64116b9 --- /dev/null +++ b/Testbed/Application.h @@ -0,0 +1,12 @@ +#include +#include + +namespace engine3d{ + class TestbedApplication : public ApplicationInstance{ + public: + TestbedApplication(const std::string& p_DebugName); + protected: + void UpdateThisApplicationInstance() override; + }; +}; + diff --git a/Testbed/CMakeLists.txt b/Testbed/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/conanfile.py b/conanfile.py index 66ccda1..cb455d0 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,22 +25,23 @@ def requirements(self): self.requires("make/4.4.1") self.tool_requires("cmake/3.27.1") self.requires("glfw/3.4", transitive_headers=True) + + # These end in 1.0 because they are engine3d-customized conan packages + # Slighly modified of the conan packages and it's CMake generators to using "Unix Makefiles" self.requires("fmt/10.2.1", transitive_headers=True) self.requires("spdlog/1.14.1", transitive_headers=True) self.requires("glm/1.0.1", transitive_headers=True) self.requires("yaml-cpp/0.8.0", transitive_headers=True) - self.requires("box2d/2.4.1", transitive_headers=True) + self.requires("box2d/2.4.2") self.requires("opengl/system", transitive_headers=True) + + # engine3d-dev customized conan packages for these dependencies + # self.requires("imguidocking/1.0") + # self.requires("joltphysics/1.0") - # Vulkan-related headers and includes packages - self.requires("vulkan-headers/1.3.268.0", transitive_headers=True) # self.requires("shaderc/2023.6") - # self.requires("joltphysics/3.0.1") # self.requires("physx/4.1.2") - # self.requires("directx-headers/1.610.2", transitive_headers=True) # self.requires("assimp/5.4.1") - # self.requires("joltphysics/3.0.1", transitive_headers=True) - # self.requires("joltphysics/3.0.1", transitive_headers=True) def config_options(self): if self.settings.os == "Windows": @@ -62,9 +63,8 @@ def generate(self): tc.generate() def build(self): - # cmake = CMake(self, generator="Unix Makefiles") cmake = CMake(self) - # cmake.verbose = True + cmake.verbose = True cmake.configure() cmake.build() diff --git a/configure.sh b/configure.sh new file mode 100644 index 0000000..e42fb1c --- /dev/null +++ b/configure.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Configuration script to configure dependencies for Engine3D + +os="$1" + +if [[ "$os" = "--linux" ]]; then + echo "Did you install the local dependencies (glfw, glm, box2d, etc.)? [y/N]" + + echo "Checking dependencies for Linux..." + echo "Installing Imgui..." + git clone https://github.com/SpinnerX/Im-Gui ~/Desktop/ + cd ~/Desktop/Im-Gui/ && mkdir build && cd build cmake .. && sudo make -j install + + echo "Installing glad..." + git clone https://github.com/SpinnerX/glad + cd ~/Desktop/glad/ && mkdir build && cd build cmake .. && sudo make -j install + + echo "Downloading Im-Guizmo..." + git clone https://github.com/SpinnerX/Im-Guizmo ~/Desktop/ + cd ~/Desktop/Im-Guizmo/ && mkdir build && cd build cmake .. && sudo make -j install +fi + +if [[ "$os" = "--mac" ]]; then + echo "Checking dependencies for Mac..." + if [ ! -z "/usr/local/include/imgui" ]; then + echo "Installing Imgui..." + git clone https://github.com/SpinnerX/Im-Gui ~/Desktop/ + cd ~/Desktop/Im-Gui/ && mkdir build && cd build cmake .. && sudo make -j install + fi + + if [ ! -z "/usr/local/include/glad" ]; then + echo "Installing glad..." + git clone https://github.com/SpinnerX/glad + cd ~/Desktop/glad/ && mkdir build && cd build cmake .. && sudo make -j install + fi + + if [ ! -z "/usr/local/include/ImGuizmo" ]; then + echo "Downloading Im-Guizmo..." + git clone https://github.com/SpinnerX/Im-Guizmo ~/Desktop/ + cd ~/Desktop/Im-Guizmo/ && mkdir build && cd build cmake .. && sudo make -j install + fi + + exit 1 +else + echo "OS \"$os\" is not supported currently!" +fi diff --git a/engine3d/Core/Renderer/Renderer.h b/engine3d/Core/Renderer/Renderer.h index 989f626..6d36b90 100644 --- a/engine3d/Core/Renderer/Renderer.h +++ b/engine3d/Core/Renderer/Renderer.h @@ -1,6 +1,5 @@ #pragma once -#include -#include + #include #include @@ -20,13 +19,6 @@ namespace engine3d{ //! @note This will be how our renderer get's initialized static void Initialize(); - - //! @note TODO -- Move this into swapchain. - //! @note We have the final pass within swapchain. - static VkRenderPass& GetCurrentRenderPass(); - - static void RenderTriangle(const vk::VulkanCommandBuffer &cmdBuffer, engine3d::vk::VulkanShaderPipelineBuilder &shaderPipeline); - //! @note Per indices will represent our rgba values /** * @param 0 = r @@ -35,52 +27,71 @@ namespace engine3d{ * @param 3 = a */ static void SetBackgroundColor(const std::array& rgba); - /** - * @name Submit - * @note Submits our tasks that are defined as callback function object - * @note This way we can have them be stored in a storage buffer. - * @note Storage buffer will handle how each tasks may operate. - * @note How this function operates? - * @note When you submit a function you do any vulkan-related logic then that function object gets rendered in the precedence order that the time each tasks been submitted. - * @note Which also vary at when each tasks get submitted - * @note The table to think about this is the following : Submit(=>[task(), task(), task(), imguiTask(), ....] -> swapchain -> presentation - * @note TODO -- Some kind of storage API to help with managing all of our tasks as part of our submission flow. - * @note Since submitting work can vary on flags and various other factors this submission allows for flexibility in types of commands to submit and how these commands are prepared. - * @note frames in flight - means to ensure syncrhonization between host and device (CPU and GPU) - * - - Example - If this was to happen in UICore or UI-related abstraction around imgui. - - // This is a quick API flow example of what the behavior would be utilizing the Renderer::Submit call - // Allowing to submit per-task based commands per submission. - // Allowing to have a generic API for submitting different tasks to render passes before sending them to the swapchain. - - // Just adding this to be clear where this code may reside at. - // In reality the instead of creating a pointer to our current instance, we might directly modify to using the "this" keyword - UICore* core = this; - Renderer::Submit([core](){ - VulkanCommandBuffer buffer = VulkanCommandBuffer::Create(...); - VulkanRenderPass renderPass = VulkanRenderPass(1, buffer.data()); - - vk::BeginRenderPass(renderPass, renderPass.BeginInfo(), flags); - vk::Begin(buffer, flags); - vk::End(buffer); - vk::EndRenderPass(renderPass); - }); - - */ - template - static void Submit(const Command&& function){ - } //! @note Will want a function to flush our scene when giving the renderer all of our context - //! @note For now this flush function is how we flush our current primitives to get them presented onto the screen. - //! @note TODO -- Move the logic that acquires next image into the vulkan abstraction static void FlushScene(); static VkClearValue* GetClearColor(); - // std::unique_ptr m_Test; + template + static void Submit(const UTask&& task){ + } + + //! @note This is what will be used to submit our color when refreshing frames. + // static void RenderClearColor(); + //! @note Testing rendering basic clear frames + static void RenderBasicClearColor(); + + static void Presentation(); + private: }; -}; \ No newline at end of file +}; + +/** + * + * + * + * + * + +!@note Changing command buffers API + + +//! @note This is equivalent to doing: +vk::Begin(m_CommandBuffer); +// Do the actual task below here +vk::End(m_CommandBuffer); + +//! @note Preferred API. Since recording tasks into command buffer may vary. +//! @note Option #1 +m_ClearColorCommandBuffer.Record([](){ + VkImageSubresourceRange imageRange = { + .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + }; + + uint32_t presentQueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamily(); + + vkCmdClearColorImage(g_ClearColorCommandBuffer, vk::VulkanSwapchain::GetImage(0), VK_IMAGE_LAYOUT_GENERAL, &clearColorValue.color, 1, &imageRange); +}); + +//! @note Option #2 + +vk::Record(m_CommandBuffer, [](){ + VkImageSubresourceRange imageRange = { + .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + }; + + uint32_t presentQueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamily(); + + vkCmdClearColorImage(g_ClearColorCommandBuffer, vk::VulkanSwapchain::GetImage(0), VK_IMAGE_LAYOUT_GENERAL, &clearColorValue.color, 1, &imageRange); +}); +*/ \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.h b/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.h new file mode 100644 index 0000000..c9b586a --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +struct GLFWwindow; +namespace engine3d{ + + namespace vk{ + /** + * @name Vulkan.h + * @note Uses for instantiating our vulkan API + * @note These are properties that will be used throughout our vulkan's backend + * @note Instantiating when we initiate the logical/physical devices. + */ + class VulkanPipeline{ + public: + static void InitializePipeline(); + void CleanupPipeline(); + static GLFWwindow* GetCurrentWindow(); + static VkInstance& GetVkInstance(); + static VkSurfaceKHR& GetVkSurface(); + static std::string& GetApplicationTitle(); + static uint32_t GetWidth(); + static uint32_t GetHeight(); + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.h new file mode 100644 index 0000000..c5364bd --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.h @@ -0,0 +1,70 @@ +#pragma once +#include +#include + +namespace engine3d{ + namespace vk{ + /** + * @name Vulkan Command Buffer + * @note Abstraction of our command buffer in Vulkan + * @note Typically there are a few stages to the command buffer lifecylcle. + * @param States Allocate (Initial) => Begin (Recording) => End (Execute) => Complete (Submission) + * @note While chechking during recording if command buffer's invalid then it'll reset back to it's initial state. + * @note If invalid just before submission then it would complete with a one-time submit(pending) then go through an invalid state before resetting to its initial state. + * + * @param MemoryFragmentation + * @note Since Vulkan allows for multiple command buffers where users can reset its initial state, be aware to onto cause memory fragmentation. + * @note For memory fragmentation, Vulkan allows for the notion of VkCommandPool (Command Buffer Pools) + * @note To think about this is an optimized memory allocator to reduce memory fragmentations tailored for these specific jobs. + * @note Addition to VkCommandPool must externally and explicitly be synchronized if you want to allocate, record, or reset commands. + * @note Better approach to this is to allocate a pool for each thread to allow safely recording different command buffers in different threads in parallel. (Which OpenGL does not allow you do to do) + */ + class VulkanCommandBuffer{ + public: + VulkanCommandBuffer() = default; +<<<<<<< HEAD + /** + * @param count is the size of command buffers this current command buffer structure contains. + */ +======= +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + VulkanCommandBuffer(uint32_t count); + ~VulkanCommandBuffer(); + + /** +<<<<<<< HEAD + * @param begin indicates when the command buffer should start recording commands + * @param end tells the command buffer where to stop recording commands. + */ + void begin(VkCommandBufferUsageFlags flags); + void end(); + + /** @note Returning our currently active command buffer **/ + VkCommandBuffer& GetActiveBuffer(uint32_t idx); + + /** @note getting size of command buffers that this wrapper for command buffers contain **/ + uint32_t Size() const; + + private: +======= + * @param CommandBuffer is the buffer that we take as the handle + * @param VkCommandUsageFlags represents the flags tell how the command buffers will be used through submission + */ + void Begin(VkCommandBuffer commandBuffer, VkCommandBufferUsageFlags usageFlags); + void End(VkCommandBuffer buffer); + + void RecordClearBackgroundColor(float r, float g, float b, float a = 1.0f); + void RecordCommandBuffers(); + + VkCommandBuffer& operator[](uint32_t idx); + + uint32_t GetCmdBufferSize(); + + private: + uint32_t m_ImagesCount = 0; // number of images +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + std::vector m_CommandBuffers; + VkCommandPool m_CommandPool; + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.h new file mode 100644 index 0000000..df31e71 --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.h @@ -0,0 +1,50 @@ +#pragma once +#include + +namespace engine3d{ + namespace vk{ + /** + * @name Vulkan Command Queue + * @note This queue will be used to submit command buffers through + * @note There are the process of submitting an image through the command buffer queue + * @param AcquireImage - getting an index to free image N. + * @param SubmitCommand - Submitting a command buffer to render to image N. + * @param Presentation - Presenting image N + */ + class VulkanCommandQueue{ + public: + VulkanCommandQueue() = default; + VulkanCommandQueue(uint32_t queueIdx); + // void Submit(std::function& attribute); + uint32_t AcquireNextImage(); + + void ResetCommandBufferToEnqueue(); + + VkQueue& GetVkQueueInstance(); + + /** + * @note Difference between SubmitAsync and SubmitSync + * @param SubmitAsync just means that we have sempahores waiting to send a signal to indicate that the rendering/pressentations finished + * @param SubmitSync means that we do not have any waiting semaphores + */ + void SubmitSync(VkCommandBuffer buffer); + void SubmitAsync(VkCommandBuffer buffer); + + void Presentation(uint32_t imgIdx); + + //! @note Should check if we're idle. + //! @note Means to hang until command queue are done with our images stored + void WaitIdle(); + + void WaitIdleFence(); + private: + VkQueue m_CmdQueue = VK_NULL_HANDLE; + VkSemaphore m_RenderCompleteSemaphore = VK_NULL_HANDLE; // signal when rendering complete + VkSemaphore m_PresentCompleteSemaphore = VK_NULL_HANDLE; // signal when presentation's completed + + VkFence m_RenderCompleteFence = VK_NULL_HANDLE; + VkFence m_PresentCompleteFence = VK_NULL_HANDLE; + VkFence m_RenderFence; + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.h new file mode 100644 index 0000000..9698113 --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.h @@ -0,0 +1,106 @@ +#pragma once +#include +#include + +namespace engine3d{ + namespace vk{ + struct PhysicalDeviceAttribute{ + VkPhysicalDevice device; // usage is to read/write or creating our actual physical object representation of our physical device + VkPhysicalDeviceProperties deviceProperties; // which is a structure that represent the properties about our GPU + std::vector queueFamProperties; // for each device there might be different queue families properties + std::vector queueSupportPresent; // different queue support that are present + std::vector surfaceFormats; // different formats such as pixels and color spaces + VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkPhysicalDeviceMemoryProperties memoryProperties; + std::vector presentModes; + VkPhysicalDeviceFeatures phsicalDeviceFeatures; + }; + + /** + * @name VulkanPhysicalDevice + * @note Abstraction of how we interact with our current physical device + * @note Checks for driver compatibilities, device suitability checks, and available queue families + * + * @note Used to expose what queue families are presented on your specific GPU. + * @note In vulkan you submid draw instructions as command buffers in queues + * @note Queues have queue families that represent different workloads the physical device exposes to you (the application developer) + * + * + * @name Requirements that would be looked for within on our current physical device hardware (GPU) + * @name Presentation Mode Topic + * @note Mentioned more when doing swap chains + * @note Typically in OpenGL handles double buffering by doing glfwSwapBuffers + * @note Double-buffering is basically having a back buffer for updating and the other buffer for displaying to the screen. + * @note Initially is how its done when you render scenes to the screen. + */ + class VulkanPhysicalDevice{ + public: + void InitializePhysicalDevice(); + void CleanupPhysicalDevice(); + //! @note Choosing if there are multiple devices + //! @note Function is used to also check if our current device supports presenting. + //! @note Something to consider is based on num of queues, size of memory, or present all devices to devs from a GUI. + uint32_t SelectDevice(VkQueueFlags ReqQueueFlag_t, bool IsSupportPresent); + + static VkSurfaceCapabilitiesKHR GetSurfaceCapabilities(); + static std::vector GetPresentationModes(); + static std::vector GetSurfaceFormats(); + VkPhysicalDevice Selected(); + VkBool32 IsGeometryShaderSupported(); + VkBool32 IsTesselationSupported(); + + VkSurfaceCapabilitiesKHR SurfaceCapabilities(); + std::vector SurfaceFormats(); + std::vector PresentationModes(); + + private: + // VkPhysicalDevice Selected(); + PhysicalDeviceAttribute SelectedDevice(); + private: + //! @note TODO -- probably have this be a std::map or something + //! @note This way we can have a faster search for the best physical device to use and quicker search time. + //! @note Rather then iterating until we find that specific physical device + std::vector m_PhysicalDevices; + int m_DeviceIdx = 0; // index to selected device + }; + + /** + * @name Vulkan Logical Device + * @note [instance] -> [physical device] -> [logical device] + * @note logical device in Vulkan means we do not interact to the physical hardware device,but the driver. + * @note + */ + class VulkanLogicalDevice{ + public: + void InitializeLogicalDevice(); + void CleanupLogicalDevice(); + + VkDevice LogicalDeviceInstance(); + + //! @note Value that stores index to the queue family + uint32_t& QueueFamily(); + private: + uint32_t m_queueFamily; + VkDevice m_Device; + }; + + /** + * @name VulkanDevice + * @note Represent our abstraction layers for physical and logical devices that are dealt within Vulkan + * @note VulkanDevice is exposed to the developer and will be frequently used when working on the vulkan abstraction + */ + class VulkanDevice{ + public: + //! @note Initiating our devices through Vulkan that are available + static void InitializeDevice(); + + //! @note Cleaning up making sure things get deallocated cleanly (if there are any) + void CleanupDevice(); + + static VkPhysicalDevice GetVkPhysicalDeviceInstance(); + static VkDevice GetVkLogicalDeviceInstance(); + static VulkanPhysicalDevice GetPhysicalDevice(); + static VulkanLogicalDevice GetLogicalDevice(); + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanPresentation.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanPresentation.h new file mode 100644 index 0000000..384f2db --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanPresentation.h @@ -0,0 +1,16 @@ +#pragma once + +namespace engine3d{ + namespace vk{ + /** + * @name VulkanPresentation + * @note Defines how we accept the swapchain to present data to our screen. + * @note [swapchain] -> [presentation] -> [screen] + */ + class VulkanPresentation{ + public: + + + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.h new file mode 100644 index 0000000..33d0c36 --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include +#include + +namespace engine3d{ + namespace vk{ + /** + * @name Vulkan Render Pass + * @note Renderpasses are where rendering occurs + * @note VkRenderPass encapsulates the idea of state needed to setup targeted rendering, state of images that'll be rendered. + * @note Renderpass is concept known to vulkan for allowing driver to know more about state of the images you render + * @note Framebuffers will be requiring a specific render pass. + * + * @note RenderPasses contains List of resources (attachments) + * @note Dependencies (Subpasses) - implying how you use subpasses when dealing with multiple buffers like shadow passing/g-buffers. + * @note Subpasses encompasses all draw commands that uses the same input and output resources + * + * @note Formats + * @note Loading/Storing Methods + * @note Layouts + * + * @note Renderpasses in an abstract manner refers to its input/output resources + * + * @note Each operation has it's own render pass. Such as deferred rendering, shadow passes would each have their own renderpass + * @note TODO -- Should think of another way to get VulkanRenderPass working. + * + * @param VK_SUBPASS_CONTENTS_INLINE specifies contents of subpass will be recorded inline in primary cmd buffer and secondary cmd buffer must not be executed within subpass + */ + class VulkanRenderPass{ + public: + VulkanRenderPass() = default; + VulkanRenderPass(const std::string& debugName); + + /** + * @note TODO --- should have Begin() and End() functions be outside of these class instances + * @note Since some of the concepts within Vulkan requires there to be vkCmdBegin* and vkCmdEnd*, I'm thinking + */ + void Begin(VkCommandBuffer buffer, VkSubpassContents contents); + void End(VkCommandBuffer buffer); + + void SetCurrentFramebuffer(uint32_t idx); + + VkRenderPassBeginInfo& GetBeginInfo(); + + VkFramebuffer& GetFramebuffer(uint32_t idx); + + VkRenderPass& GetVkRenderPass(); + + private: + std::vector m_Framebuffers; + VkRenderPass m_RenderPass; + + }; + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.h b/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.h new file mode 100644 index 0000000..047eab4 --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include + +namespace engine3d{ + namespace vk{ + /** + * @name VulkanSwapchain + * @note TODO --- Make this part of the swap chain base class as we may want to enable devs to switch from vulkan to directx11/12 in the future. + * @note Abstraction for how Vulkan handles swapchain. + */ + + /** + * @name Vulkan Swap Chain + * @note Swap chains allow us to do things like shadow and lighting passes for deferred rendering + * @note moving images from the actual application to display. + * @note Handles format and presentation modes, containing multiple images before displaying to the actual display from application. + * @note Vulkan supports double-buffers which just means switching from back and front buffers. + * @note Switching frames are referred to in Vulkan as presentation modes + */ + class VulkanSwapchain{ + public: + ~VulkanSwapchain(); + + //! @note Initiating our vulkan swapchain. + static void InitializeSwaphchain(); + + //! @note Getting our image/image view from our swapchain + static uint32_t GetImagesSize(); + static VkImage& GetImage(uint32_t index); + static VkImageView& GetImageView(uint32_t index); + + //! @note Fetch the swapchain handler + static VkSwapchainKHR& GetVkSwapchainInstance(); + }; + }; // end of vk namespace +}; \ No newline at end of file diff --git a/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h b/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h new file mode 100644 index 0000000..7329b18 --- /dev/null +++ b/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +namespace engine3d::vk{ + /** + * @name begin + * @param buffer is the command buffer to record too. + * @param p_UsageFlags are for specifying how we want to record our commands + */ + void begin(const VkCommandBuffer& buffer, VkCommandBufferUsageFlags p_UsageFlags); + + /** + * @param buffer is the command buffer for stopping recording too. + */ + void end(const VkCommandBuffer& buffer); + + /** + * @name record + * @note Collecting our command to send to the specified command buffer + * @param commandBuffer is the buffer we want to record our commands to + * @param VkCommandBufferUsageFlags is the flags to set when we start recording commands to our command buffer + * @param UCommand will enable users to define what specifications of our commands we want to record. + */ + template + void record(VulkanCommandBuffer& commandBuffer, VkCommandBufferUsageFlags flags, const UCommand& p_CommandToCollect){ + for(uint32_t currCmdBufferIdx = 0; currCmdBufferIdx < commandBuffer.Size(); currCmdBufferIdx++){ + auto& buffer = commandBuffer.GetActiveBuffer(currCmdBufferIdx); + + begin(buffer, flags); + p_CommandToCollect(buffer, currCmdBufferIdx); + end(buffer); + } + } +}; \ No newline at end of file diff --git a/engine3d/Core/backend/internal/BaseWindowInstance.h b/engine3d/Core/backend/internal/BaseWindowInstance.h new file mode 100644 index 0000000..b30647a --- /dev/null +++ b/engine3d/Core/backend/internal/BaseWindowInstance.h @@ -0,0 +1,30 @@ +#pragma once +#include + +namespace engine3d{ + /** + * @name Window + * @name Interface for enabling usres to customize for multi-monitors + * + * @note There are a few API's that I want to go with this. + * @note The API's should be flexible in a sense of allowing users to implement their own customizable monitors. + * @note Implementing their own versions of a window instance + * + * @note Some API's helper functions would be: + * + * @note Being able to mirror to two monitors. If needed. + * engine3d::mirror(m_Window1, m_Window2); + * + * @note Split - meaning that we are writing to two swapchains + * @note Keep in mind -- per window monitor there can only be one swapchain. + * engine3d::split(m_Window1, m_Window2); + * + * @note Before I forget --- Here are some TODO's for windowing system + * @note Windows knows about the swapchain and framebuffer and images. + * @note Having a generic enough API that works across windowing systems. That is also quite sensible. + */ + class BaseWindowInstance{ + public: + VkSwapchainKHR& GetCurrentSwapchain(); + }; +}; \ No newline at end of file diff --git a/engine3d/Core/backend/internal/Window.h b/engine3d/Core/backend/internal/Window.h deleted file mode 100644 index 982ca6f..0000000 --- a/engine3d/Core/backend/internal/Window.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace engine3d{ - class Window{ - public: - static void CreateWindowInstance(); - }; -}; \ No newline at end of file diff --git a/imgui.ini b/imgui.ini index ee65558..9c087bb 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,5 +1,5 @@ [Window][Debug##Default] -Pos=60,60 +Pos=60,20 Size=400,400 Collapsed=0 @@ -8,5 +8,16 @@ Pos=1204,293 Size=372,295 Collapsed=0 +[Window][Hello, world!] +ViewportPos=875,333 +ViewportId=0xEBE6C6E6 +Size=329,305 +Collapsed=0 + +[Window][Hello] +Pos=60,60 +Size=32,35 +Collapsed=0 + [Docking][Data] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 46ea5f4..02252e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,14 +29,15 @@ set( ../${ENGINE_INCLUDE_NAME}/Core/Window.h # backend/Vulkan Sources - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Vulkan.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanDevice.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanSwapchain.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanCommandBuffer.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanCommandBuffer.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanRenderPass.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderModule.h - ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderPipelineBuilder.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/helper-functions.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/Vulkan.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanDevice.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanSwapchain.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.h + ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanRenderPass.h + # ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderModule.h + # ../${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderPipelineBuilder.h ../${ENGINE_INCLUDE_NAME}/Core/Renderer/Renderer.h ../${ENGINE_INCLUDE_NAME}/Core/Engine/Engine3D.h @@ -73,14 +74,18 @@ set( ${ENGINE_INCLUDE_NAME}/Core/backend/utilities/helper_functions.cpp # backend/Vulkan Sources - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Vulkan.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanDevice.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanSwapchain.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanCommandBuffer.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanCommandQueue.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/VulkanRenderPass.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderModule.cpp - ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderPipelineBuilder.cpp +<<<<<<< HEAD + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/helper-functions.cpp +======= +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/Vulkan.cpp + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanDevice.cpp + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanSwapchain.cpp + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.cpp + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.cpp + ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan-Experiemental/VulkanRenderPass.cpp + # ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderModule.cpp + # ${ENGINE_INCLUDE_NAME}/Core/backend/Vulkan/Shaders/VulkanShaderPipelineBuilder.cpp ${ENGINE_INCLUDE_NAME}/Core/Renderer/Renderer.cpp diff --git a/src/engine3d/Core/Renderer/Renderer.cpp b/src/engine3d/Core/Renderer/Renderer.cpp index 43f339f..32419fd 100644 --- a/src/engine3d/Core/Renderer/Renderer.cpp +++ b/src/engine3d/Core/Renderer/Renderer.cpp @@ -1,203 +1,128 @@ -#include "Core/Event/InputPoll.h" -#include -#include -#include -#include -#include -#include -#include +<<<<<<< HEAD +#include +#include +#include +#include #include +#include +======= +#include "backend/Vulkan/VulkanCommandBuffer.h" +#include "backend/Vulkan/VulkanCommandQueue.h" +#include "backend/Vulkan/VulkanSwapchain.h" +#include +#include +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f +#include +#include #include -#include +#include #include -#include -#include -#include +<<<<<<< HEAD +#include +======= +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f namespace engine3d{ - // template - // static auto buf = [](const auto& x) noexcept(noexcept(x + 1)) -> decltype(x + 1) { return x + 1; }; - - // struct RendererProperties{ - // vk::VulkanCommandBuffer m_CommandBuffer; - // vk::VulkanCommandQueue m_CommandQueue; - // vk::VulkanRenderPass m_RenderPass; - // // vk::VulkanShaderModule m_TriangleShaderVertModule; - // // vk::VulkanShaderModule m_TriangleShaderFragModule; - // // vk::VulkanShaderPipelineBuilder m_ShaderPipeline; - - // // vk::VulkanShaderModule m_RedTriangleShaderVertModule; - // // vk::VulkanShaderModule m_RedTriangleShaderFragModule; - // // vk::VulkanShaderPipelineBuilder m_RedShaderPipeline; - // VkClearColorValue color; // rgba color - // VkClearValue clearValue; - - // int m_SelectedShaderIdx = 0; - // }; - - // static RendererProperties g_properties; - - // void Renderer::Initialize(){ - // ConsoleLogInfo("Renderer::Initialize() created!"); - - // //! @note Initializes core vulkan API - // //! @note Update -- Moved to Core.cpp - - // g_properties.m_CommandBuffer = vk::VulkanCommandBuffer(vk::VulkanSwapchain::GetImagesSize()); - - // //! @param index, zero - indicates getting first data in queue at index 0 (zero) - // //! @note TODO -- for cmd buffers/queues, shader modules, and render passes. Figuring out what parameters are important that users should specify when creating this instance - // //! @note This is because as it stands the API requires for instancing the object before initializing it, but should just utilize the constructor to cleanup the API for initiating our object's lifetimes. - // g_properties.m_CommandQueue = vk::VulkanCommandQueue(0); - // g_properties.m_RenderPass = vk::VulkanRenderPass("First render pass"); - // // g_properties.m_RenderPass.InitializeRenderPass(); - - // //! @note TODO -- Compress how these shaders are loaded into a single abstraction. - - // //! @note Color palette shader - // // g_properties.m_TriangleShaderVertModule = vk::VulkanShaderModule(std::filesystem::current_path().string() + "/Resources/shaders/TriangleShader/triangle.vert.spirv"); - // // g_properties.m_TriangleShaderFragModule = vk::VulkanShaderModule(std::filesystem::current_path().string() + "/Resources/shaders/TriangleShader/triangle.frag.spirv"); - // // g_properties.m_ShaderPipeline = vk::VulkanShaderPipelineBuilder(g_properties.m_TriangleShaderVertModule.GetVkShaderModuleInstance(), g_properties.m_TriangleShaderFragModule.GetVkShaderModuleInstance(), g_properties.m_RenderPass.GetVkRenderPass()); - - // // //! @note Red triangle - // // g_properties.m_RedTriangleShaderVertModule = vk::VulkanShaderModule(std::filesystem::current_path().string() + "/Resources/shaders/TriangleShader/RedTriangle.vert.spirv"); - // // g_properties.m_RedTriangleShaderFragModule = vk::VulkanShaderModule(std::filesystem::current_path().string() + "/Resources/shaders/TriangleShader/RedTriangle.frag.spirv"); - // // g_properties.m_RedShaderPipeline = vk::VulkanShaderPipelineBuilder(g_properties.m_RedTriangleShaderVertModule.GetVkShaderModuleInstance(), g_properties.m_RedTriangleShaderFragModule.GetVkShaderModuleInstance(), g_properties.m_RenderPass.GetVkRenderPass()); - // // g_properties.m_RedShaderPipeline = vk::VulkanShaderPipelineBuilder(g_properties.m_RedTriangleShaderVertModule, g_properties.m_RedTriangleShaderFragModule, g_properties.m_RenderPass); - - - // auto buf = [=](int x, int y) mutable throw() -> int { - // int n = (x + y); - // return n; - // }; - // } - - // void Renderer::SetBackgroundColor(const std::array& rgba){ - // g_properties.clearValue.color = {rgba[0], rgba[1], rgba[2], rgba[3]}; - // } - - // //! @note Typically when we submit everything (context of our scene) then we flush that scene into render pass just before we render and send that to the screen. - // void Renderer::FlushScene(){ - // // g_properties.m_CommandBuffer.RecordClearBackgroundColor(rgba[0], rgba[1], rgba[2], rgba[3]); - - // // VkClearColorValue clearColorValue = { 0.0f, 0.5f, 0.5f, 0.f}; - - // // Clearing screen - // //! @note TODO -- may use the function call that already does this. Should improve the renderer API so we can do primitives and involve shaders as well. - // //! @note Probably will use the function RecordClearBackgroundColor(...) but doing it manually to see how I may want to - // VkImageSubresourceRange imgRange = { - // .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - // .baseMipLevel = 0, - // .levelCount = 1, - // .baseArrayLayer = 0, - // .layerCount = 1 - // }; - - // uint32_t presentQueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); - - // //! @note Command buffers for our images - // // for(int i = 0; i < g_properties.m_CommandBuffer.GetCmdBufferSize(); i++){ - // // auto& cmdBuffer = g_properties.m_CommandBuffer[i]; - - // //! @note TODO -- Take out any framebuffer-related logic out of renderpass - // //! @note Need to assign our framebuffers to our render pass. - // // vk::VulkanSwapchain::SetCurrentFramebuffer(i); - // // g_properties.m_RenderPass.SetCurrentFramebuffer(i); - - // // vk::VulkanSwapchain::DrawCommandBuffer(cmdBuffer); - - // // if(InputPoll::IsKeyPressed(ENGINE_KEY_W)){ - // // vk::VulkanSwapchain::DrawTriangle(cmdBuffer, g_properties.m_RedShaderPipeline); - // // } - // // else{ - // // vk::VulkanSwapchain::DrawTriangle(cmdBuffer, g_properties.m_ShaderPipeline); - // // } - // // g_properties.m_RenderPass.SetCurrentFramebuffer(i); - - // // vk::Begin(cmdBuffer, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); - // // g_properties.m_RenderPass.Begin(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); - // // // VkPipeline pipeline = g_properties.m_ShaderPipeline.GetVkPipeline(); - - // // if(InputPoll::IsKeyPressed(ENGINE_KEY_W)){ - // // vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_properties.m_RedShaderPipeline.GetVkPipeline()); - // // // vkCmdDraw(cmdBuffer, 3, 1, 0, 0); - // // } - // // else{ - // // vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_properties.m_ShaderPipeline.GetVkPipeline()); - // // // vkCmdDraw(cmdBuffer, 3, 1, 0, 0); - // // } - // // vkCmdDraw(cmdBuffer, 3, 1, 0, 0); - - // // g_properties.m_RenderPass.End(cmdBuffer); - // // vk::End(cmdBuffer); - // // } - - // //! @note Retrieving our images that will be used to rendering to our display. - // uint32_t idx = g_properties.m_CommandQueue.AcquireNextImage(); - // g_properties.m_CommandQueue.WaitIdleFence(); - // g_properties.m_CommandQueue.SubmitAsync(g_properties.m_CommandBuffer[idx]); - // g_properties.m_CommandQueue.Presentation(idx); - // g_properties.m_CommandQueue.WaitIdleFence(); - // } - - // VkClearValue* Renderer::GetClearColor(){ - // return &g_properties.clearValue; - // } - - // VkRenderPass& Renderer::GetCurrentRenderPass(){ return g_properties.m_RenderPass.GetVkRenderPass(); } - - /// @brief //////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// struct RendererProperties{ - vk::VulkanCommandBuffer m_CommandBuffer; - vk::VulkanCommandQueue m_CommandQueue; - vk::VulkanRenderPass m_RenderPass; - vk::VulkanShaderModule m_TriangleShaderVertModule; - vk::VulkanShaderModule m_TriangleShaderFragModule; - vk::VulkanShaderPipelineBuilder m_ShaderPipeline; - VkClearColorValue color; // rgba color - VkClearValue clearValue; + }; - static RendererProperties g_properties; + // static VkClearValue clearColorValue; + + // //! @note creating, recording, and submitting command buffers + // static VkCommandPool g_ClearColorCmdPool; + // static VkCommandBuffer g_ClearColorCommandBuffer; + // static VkQueue g_MainSubmissionQueue; + // static VkFence g_ClearColorFence; + // // static uint32_t g_CurrentImageFrameIdx = 0; + + // //! @note Semaphores + // static VkSemaphore g_PresentationCompletedSemaphore, g_RendererCompletedSemaphore; + + static vk::VulkanCommandBuffer g_CommandBuffer; + static vk::VulkanCommandQueue g_CommandQueue; + static vk::VulkanRenderPass g_CommandRenderPass; + static VkClearValue g_ClearColorValue; void Renderer::Initialize(){ - ConsoleLogInfo("Renderer::Initialize() created!"); - - //! @note Initializes core vulkan API - vk::VulkanPipeline::InitializePipeline(); // initializes our vulakn API - vk::VulkanDevice::InitializeDevice(); // initializes our physical/logical devices - vk::VulkanSwapchain::InitializeSwaphchain(); // initializes our swapchain and our VkImage/VkImageView's - - g_properties.m_CommandBuffer = vk::VulkanCommandBuffer(vk::VulkanSwapchain::GetImagesSize()); - - //! @param index, zero - indicates getting first data in queue at index 0 (zero) - //! @note TODO -- for cmd buffers/queues, shader modules, and render passes. Figuring out what parameters are important that users should specify when creating this instance - //! @note This is because as it stands the API requires for instancing the object before initializing it, but should just utilize the constructor to cleanup the API for initiating our object's lifetimes. - g_properties.m_CommandQueue = vk::VulkanCommandQueue(0); - g_properties.m_RenderPass = vk::VulkanRenderPass("First render pass"); - // g_properties.m_RenderPass.InitializeRenderPass(); - // g_properties.m_RenderPass.InitializeFramebuffers(); - g_properties.m_TriangleShaderVertModule = vk::VulkanShaderModule("Resources/shaders/TriangleShader/triangle.vert.spirv"); - g_properties.m_TriangleShaderFragModule = vk::VulkanShaderModule("Resources/shaders/TriangleShader/triangle.frag.spirv"); - } - - void Renderer::SetBackgroundColor(const std::array& rgba){ - g_properties.clearValue.color = {rgba[0], rgba[1], rgba[2], rgba[3]}; - // g_properties.m_CommandBuffer.RecordClearBackgroundColor(rgba[0], rgba[1], rgba[2], rgba[3]); - - // VkClearColorValue clearColorValue = { 0.0f, 0.5f, 0.5f, 0.f}; - - // Clearing screen - //! @note TODO -- may use the function call that already does this. Should improve the renderer API so we can do primitives and involve shaders as well. - //! @note Probably will use the function RecordClearBackgroundColor(...) but doing it manually to see how I may want to + g_CommandBuffer = vk::VulkanCommandBuffer(vk::VulkanSwapchain::GetImagesSize()); +<<<<<<< HEAD + // g_CommandBuffer = vk::VulkanCommandBuffer(2); + g_CommandQueue = vk::VulkanCommandQueue(0); + g_CommandRenderPass = vk::VulkanRenderPass("Clear Render Pass"); + } + + void Renderer::SetBackgroundColor(const std::array &rgba){ + for(size_t i = 0; i < rgba.size(); i++){ + g_ClearColorValue.color.float32[i] = rgba[i]; + } + } + +======= + g_CommandQueue = vk::VulkanCommandQueue(0); + g_CommandRenderPass = vk::VulkanRenderPass("Clear Render Pass"); + + // vkGetDeviceQueue(vk::VulkanDevice::GetVkLogicalDeviceInstance(), vk::VulkanDevice::GetLogicalDevice().QueueFamily(), 0, &g_MainSubmissionQueue); + + // VkSemaphoreCreateInfo createInfo = { + // .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + // .pNext = nullptr, + // .flags = 0 + // }; + + // //! @note Instantiating our sempahore handler + // VkResult presentationSemaphoreRes = vkCreateSemaphore(vk::VulkanDevice::GetVkLogicalDeviceInstance(), &createInfo, nullptr, &g_PresentationCompletedSemaphore); + // VkResult rendererSemaphoreRes = vkCreateSemaphore(vk::VulkanDevice::GetVkLogicalDeviceInstance(), &createInfo, nullptr, &g_RendererCompletedSemaphore); + + // //! @note Then validating if the creation of the semaphore object was valid. + // if(presentationSemaphoreRes != VK_SUCCESS){ + // ConsoleLogError("vkCreateSemaphore error message is {}", vk::VkResultToString(presentationSemaphoreRes)); + // } + + // if(rendererSemaphoreRes != VK_SUCCESS){ + // ConsoleLogError("vkCreateSemaphore error message is {}", vk::VkResultToString(rendererSemaphoreRes)); + // } + + // //! @note Initializing VkCommandBuffer + // VkCommandPoolCreateInfo clearCmdPool = { + // .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + // .pNext = nullptr, + // .flags = 0, + // .queueFamilyIndex = vk::VulkanDevice::GetLogicalDevice().QueueFamily() + // }; + + // VkResult cmdPoolResult = vkCreateCommandPool(vk::VulkanDevice::GetVkLogicalDeviceInstance(), &clearCmdPool, nullptr, &g_ClearColorCmdPool); + + // if(cmdPoolResult != VK_SUCCESS){ + // ConsoleLogError("vkCreateCommandPool errored message!===>=\t\t{}", vk::VkResultToString(cmdPoolResult)); + // } + + // VkCommandBufferAllocateInfo cmdBufAllocInfo = { + // .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + // .pNext = nullptr, + // .commandPool = g_ClearColorCmdPool, + // .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + // .commandBufferCount = 1 + // }; + + // VkResult cmdBufAllocResult = vkAllocateCommandBuffers(vk::VulkanDevice::GetVkLogicalDeviceInstance(), &cmdBufAllocInfo, &g_ClearColorCommandBuffer); + + // if(cmdBufAllocResult != VK_SUCCESS){ + // ConsoleLogError("vkAllocateCommandBuffers error because was unsuccessful in VulkanCommandBuffer.cpp: VulkanCommandBuffer::VulkanCommandBuffer()!"); + // } + + + } + + void Renderer::SetBackgroundColor(const std::array &rgba){ + /* clearColorValue.color.float32 = rgba.data(); */ + for(size_t i = 0; i < rgba.size(); i++){ + g_ClearColorValue.color.float32[i] = rgba[i]; + } + } + +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + void Renderer::RenderBasicClearColor(){ VkImageSubresourceRange imgRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, @@ -206,67 +131,114 @@ namespace engine3d{ .layerCount = 1 }; - uint32_t presentQueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); +<<<<<<< HEAD + /* + void Begin(VkCommandBuffer commandBuffer, VkCommandBufferUsageFlags usageFlags){ + VkCommandBufferBeginInfo beginInfo{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = usageFlags, + .pInheritanceInfo = nullptr + }; + + VkResult res = vkBeginCommandBuffer(commandBuffer, &beginInfo); + if(res != VK_SUCCESS){ + ConsoleLogError("vkBeginCommandBuffer error message is ==> {}", VkResultToString(res)); + } + } + + void End(VkCommandBuffer buffer){ + VkResult res = vkEndCommandBuffer(buffer); + if(res != VK_SUCCESS){ + ConsoleLogError("vkEndCommandBuffer errored message is {}", VkResultToString(res)); + } + } + */ + + //! @note Replace the following code below with: + /* + VkCommandBufferUsageFlagBits flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + vk::record(cmdBuffer, flags, [](){ + + }); + */ + /* + Format + + BeginCmdBuffer(); + BeginRenderPass(); + + Actual rendering commands... + + EndRenderPass(); + EndCmdBuffer(); + + */ + /* + // OLD VERSION OF THE API + for(int i = 0; i < g_CommandBuffer.GetCmdBufferSize(); i++){ + auto& cmdBuffer = g_CommandBuffer[i]; + g_CommandRenderPass.SetCurrentFramebuffer(i); + + vk::Begin(cmdBuffer, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); + g_CommandRenderPass.Begin(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); + + g_CommandRenderPass.End(cmdBuffer); + vk::End(cmdBuffer); + } + */ + + // NEW API + VkCommandBufferUsageFlags flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + vk::record(g_CommandBuffer, flags, [&renderPass = g_CommandRenderPass](VkCommandBuffer& buffer, uint32_t currentCmdBufferFrameIdx){ + renderPass.SetCurrentFramebuffer(currentCmdBufferFrameIdx); + renderPass.Begin(buffer, VK_SUBPASS_CONTENTS_INLINE); + renderPass.End(buffer); + }); + + //! @note Recording another set of commands. + // VkCommandBufferUsageFlags flags2 = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + // vk::record(g_CommandBuffer, flags2, [&renderPass = g_CommandRenderPass](VkCommandBuffer& buffer, uint32_t currentCmdBufferFrameIdx){ + // renderPass.SetCurrentFramebuffer(currentCmdBufferFrameIdx); + // renderPass.Begin(buffer, VK_SUBPASS_CONTENTS_INLINE); + // renderPass.End(buffer); + // }); + } + + void Renderer::Presentation(){ + /** + @note Thinking of a better way of handling presentation. + @note So when we get to shaders, we can at least not worry about the miniscule steps that make our API more prone to bugs. - //! @note Command buffers for our images - for(int i = 0; i < g_properties.m_CommandBuffer.GetCmdBufferSize(); i++){ - // VkImageMemoryBarrier presentationToClearBarrier = {}; - // presentationToClearBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - // presentationToClearBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - // presentationToClearBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - // presentationToClearBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - // presentationToClearBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - // presentationToClearBarrier.srcQueueFamilyIndex = presentQueueFamily; - // presentationToClearBarrier.dstQueueFamilyIndex = presentQueueFamily; - // presentationToClearBarrier.image = vk::VulkanSwapchain::GetImage(i); - // presentationToClearBarrier.subresourceRange = imgRange; - - // // Change layout of image to be optimal for presenting - // VkImageMemoryBarrier clearToPresentBarrer = {}; - // clearToPresentBarrer.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - // clearToPresentBarrer.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - // clearToPresentBarrer.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - // clearToPresentBarrer.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - // clearToPresentBarrer.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - // clearToPresentBarrer.srcQueueFamilyIndex = presentQueueFamily; - // clearToPresentBarrer.dstQueueFamilyIndex = presentQueueFamily; - // clearToPresentBarrer.image = vk::VulkanSwapchain::GetImage(i); - // clearToPresentBarrer.subresourceRange = imgRange; - - vk::Begin(g_properties.m_CommandBuffer[i], VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); - - // g_properties.m_RenderPass.().framebuffer = g_properties.m_RenderPass.GetFramebuffer(i); - g_properties.m_RenderPass.SetCurrentFramebuffer(i); - // g_properties.m_RenderPass.SetCurrentFramebuffer(i); - // g_properties.m_RenderPass - vkCmdBeginRenderPass(g_properties.m_CommandBuffer[i], &g_properties.m_RenderPass.GetVkRenderpassBeginInfo(), VK_SUBPASS_CONTENTS_INLINE); - // g_properties.m_RenderPass.Begin(g_properties.m_CommandBuffer[i], VK_SUBPASS_CONTENTS_INLINE); - - // vkCmdPipelineBarrier(g_properties.m_CommandBuffer[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - // 0, // dependency flags - // 0, nullptr, // memory barriers - // 0, nullptr, // buffer memory barriers - // 1, &presentationToClearBarrier); - - // vkCmdClearColorImage(g_properties.m_CommandBuffer[i], vk::VulkanSwapchain::GetImage(i), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &g_properties.clearValue.color, 1, &imgRange); - // vkCmdPipelineBarrier(g_properties.m_CommandBuffer[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &clearToPresentBarrer); - - // g_properties.m_RenderPass.End(g_properties.m_CommandBuffer[i]); - vkCmdEndRenderPass(g_properties.m_CommandBuffer[i]); - vk::End(g_properties.m_CommandBuffer[i]); + */ + uint32_t idx = g_CommandQueue.AcquireNextImage(); + g_CommandQueue.WaitIdleFence(); + g_CommandQueue.SubmitAsync(g_CommandBuffer.GetActiveBuffer(idx)); + g_CommandQueue.Presentation(idx); + g_CommandQueue.WaitIdleFence(); + } + +======= + for(int i = 0; i < g_CommandBuffer.GetCmdBufferSize(); i++){ + auto& cmdBuffer = g_CommandBuffer[i]; + g_CommandRenderPass.SetCurrentFramebuffer(i); + + vk::Begin(cmdBuffer, VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); + g_CommandRenderPass.Begin(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); + + g_CommandRenderPass.End(cmdBuffer); + vk::End(cmdBuffer); } - } - - //! @note Typically when we submit everything (context of our scene) then we flush that scene into render pass just before we render and send that to the screen. - void Renderer::FlushScene(){ - uint32_t idx = g_properties.m_CommandQueue.AcquireNextImage(); - g_properties.m_CommandQueue.WaitIdleFence(); - g_properties.m_CommandQueue.SubmitAsync(g_properties.m_CommandBuffer[idx]); - g_properties.m_CommandQueue.WaitIdleFence(); - g_properties.m_CommandQueue.Presentation(idx); - } - - VkClearValue* Renderer::GetClearColor(){ - return &g_properties.clearValue; - } -}; \ No newline at end of file + } + + void Renderer::Presentation(){ + uint32_t idx = g_CommandQueue.AcquireNextImage(); + g_CommandQueue.WaitIdleFence(); + g_CommandQueue.SubmitAsync(g_CommandBuffer[idx]); + g_CommandQueue.Presentation(idx); + g_CommandQueue.WaitIdleFence(); + } + +>>>>>>> fa59aaf07c9cbf80f5d25918c4d43b3cca25238f + VkClearValue* Renderer::GetClearColor(){ return &g_ClearColorValue; } +}; diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.cpp new file mode 100644 index 0000000..b0559c6 --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/Vulkan.cpp @@ -0,0 +1,208 @@ +#include +#include +#include +#include + +#define VK_USE_PLATFORM_WIN32_KHR +#define GLFW_INCLUDE_VULKAN +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include + +namespace engine3d::vk{ + // namespace vk{ + + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT Severity, + VkDebugUtilsMessageTypeFlagsEXT Type, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData + ){ + ConsoleLogWarn("Debug callback: {}\n", pCallbackData->pMessage); + ConsoleLogWarn("\tSeverity {}", GetDebugSeverity(Severity)); + ConsoleLogWarn("\tType {}", GetDebugType(Type)); + ConsoleLogWarn("\tObjects"); + + for(uint32_t i = 0; i < pCallbackData->objectCount; i++){ + ConsoleLogWarn("{} ", pCallbackData->pObjects[i].objectHandle); + } + + return false; + } + + static std::vector validationLayers = { + "VK_LAYER_KHRONOS_validation" + }; + + static std::vector extensions{ + VK_KHR_SURFACE_EXTENSION_NAME, // Used to bind our window to vulkan +#if defined(_WIN32) + "VK_KHR_win32_surface", +#elif defined(__APPLE__) + "VK_MVK_macos_surface", +#elif defined(__linux__) + "VK_KHR_xcb_surface", +#endif + // enables callback to our application when errors happen in vulkan + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + }; + + //! @note Properties for our current window application. + struct WindowApplicationProperties{ + uint32_t width, height; + std::string title; + }; + + //! @note Initializing debug messenger + void make_debug_messenger(){ + VkDebugUtilsMessengerCreateInfoEXT debugMsgCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .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, + .pfnUserCallback = &DebugCallback, + .pUserData = nullptr + }; + } + + //! @note TODO -- Would be better to rename VulkanProperties to VulkanContext + //! @note Since this is really what it is doing + struct VulkanProperties{ + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkInstance instance = VK_NULL_HANDLE; + VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + WindowApplicationProperties windowProperties; + GLFWwindow* glfwWindowInstance; + }; + + static VulkanProperties g_properties; + + void VulkanPipeline::InitializePipeline(){ + if(!glfwInit()){ + ConsoleLogError("glfwInit() failed to initialize GLFW!"); + assert(false); + } + + if(!glfwVulkanSupported()){ + ConsoleLogError("vulkan loader and ICD was not found on this current device!"); + } + + //! @note TODO --- Setting our window dimensions to be based on our current window's monitor dimensions. + // glfwGetMonitorP + // GLFWvidmode currentWindow; + // glfwGetDesktopMode(¤tWindow); + + g_properties.windowProperties.width = 800; + g_properties.windowProperties.height = 600; + g_properties.windowProperties.title = "Engine3D"; + + // GLFWvidmode* mode = (GLFWvidmode *)glfwGetVideoMode(glfwGetPrimaryMonitor()); + + // glfwInitHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + g_properties.glfwWindowInstance = glfwCreateWindow(g_properties.windowProperties.width, g_properties.windowProperties.height, g_properties.windowProperties.title.c_str(), nullptr, nullptr); + + glfwMakeContextCurrent(g_properties.glfwWindowInstance); + + if(!g_properties.glfwWindowInstance){ + ConsoleLogError("glfwWindowInstance window pointer was nullptr! Make sure glfwInit() initialized!"); + assert(false); + } + + VkApplicationInfo appInfo{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = g_properties.windowProperties.title.c_str(), + .pEngineName = g_properties.windowProperties.title.c_str(), + .engineVersion = VK_MAKE_API_VERSION(1, 1, 0, 0), + .apiVersion = VK_API_VERSION_1_0 + }; + + VkInstanceCreateInfo createInfo{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, // reserve for future use + .pApplicationInfo = &appInfo, + .enabledLayerCount = (uint32_t)validationLayers.size(), //! list of extensions. Up to app developer to make sure if these are supported + .ppEnabledLayerNames = validationLayers.data(), + .enabledExtensionCount = (uint32_t)extensions.size(), + .ppEnabledExtensionNames = extensions.data() + }; + + //! @note Setting up Vulkan instance that will be for initiating the Vulkan API. + //! @note We do not have a customized allocator for now we set that param to a nullptr. + VkResult res = vkCreateInstance(&createInfo, nullptr, &g_properties.instance); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateInstance() was not successful in InitializePipeline() in file Vulkan.cpp"); + assert(false); + } + + // make_debug_messenger(); + //! @note Debug callback requires validatoin layers and debug utils to be enabled in extensions as it is not part of the vulkan core. + VkDebugUtilsMessengerCreateInfoEXT debugMsgCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .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, + .pfnUserCallback = &DebugCallback, + .pUserData = nullptr + }; + + //! @note Creating our surface + //! @note TODO -- Probably want to abstract this and deal with window surfaces using Vulkan and the targeted platforms-specific windowing system + VkResult surface_res = glfwCreateWindowSurface(g_properties.instance, g_properties.glfwWindowInstance, nullptr, &g_properties.surface); + + if(surface_res != VK_SUCCESS){ + ConsoleLogError("glfwCreateWindowSurface errored message is ===>\t\t{}", VkResultToString(surface_res)); + } + // CreateSurface(); + } + + void VulkanPipeline::CleanupPipeline(){ + // vkDestroyDebugUtilsMessenger(g_properties.instance, g_properties.debugMessenger, nullptr); + PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessenger = VK_NULL_HANDLE; + vkDestroyDebugUtilsMessenger = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(g_properties.instance, "vkDestroyDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessenger(g_properties.instance, g_properties.debugMessenger, nullptr); + if(!vkDestroyDebugUtilsMessenger){ + ConsoleLogError("Cannot fnid address of vkDestroyDebugUtilsMessenger"); + } + + PFN_vkDestroySurfaceKHR vkDestroySurface = VK_NULL_HANDLE; + vkDestroySurface = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(g_properties.instance, "vkDestroySurfaceKHR"); + + if(!vkDestroySurface){ + ConsoleLogError("Cannot find address of vkDestroySurfaceKHR"); + } + + vkDestroyInstance(g_properties.instance, nullptr); + } + + // VulkanProperties& VulkanPipeline::GetVulkanProperties(){ return g_properties; } + + GLFWwindow* VulkanPipeline::GetCurrentWindow(){ + return g_properties.glfwWindowInstance; + } + + VkInstance& VulkanPipeline::GetVkInstance(){ return g_properties.instance; } + + VkSurfaceKHR& VulkanPipeline::GetVkSurface(){ return g_properties.surface; } + + std::string& VulkanPipeline::GetApplicationTitle() { + return g_properties.windowProperties.title; + } + + uint32_t VulkanPipeline::GetWidth() { + return g_properties.windowProperties.width; + } + + uint32_t VulkanPipeline::GetHeight() { + return g_properties.windowProperties.height; + } + + // }; + +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.cpp new file mode 100644 index 0000000..92bff2b --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandBuffer.cpp @@ -0,0 +1,130 @@ +#include "Core/backend/Vulkan-Experiemental/VulkanSwapchain.h" +#include "Core/backend/utilities/helper_functions.h" +#include +#include +#include +#include + +namespace engine3d::vk{ + /** + * @note We create a single command pool for our command buffer + * @note We create a single command buffer with the information on how they should do allocation tasks. + * @note TODO -- command pools should be in a different implementation task as later on we may be dealing with mutliple command buffers + * @note Where we may want to record these commands, reset them, or even allocate them in parallel + */ + VulkanCommandBuffer::VulkanCommandBuffer(uint32_t commandBufferSizeCount) { + //! @note Initializing Command Buffer Pool + //! @note TODO --- Having this be a separate implementation since we will be dealing with multiple command buffers in the future. + //! @note For now we will have command pool in here. + // m_ImagesCount = imageSizeCount; + VkCommandPoolCreateInfo commandPoolCreateInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = VulkanDevice::GetLogicalDevice().QueueFamily(), + }; + + m_CommandBuffers.resize(commandBufferSizeCount); + + VkResult res = vkCreateCommandPool(VulkanDevice::GetVkLogicalDeviceInstance(), &commandPoolCreateInfo, nullptr, &m_CommandPool); + + //! @note Creating our command buffers and initiating the command buffer information for allocation + VkCommandBufferAllocateInfo commandBufAllocInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = m_CommandPool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = (uint32_t)m_CommandBuffers.size() + }; + + VkResult allocateResult = vkAllocateCommandBuffers(VulkanDevice::GetVkLogicalDeviceInstance(), &commandBufAllocInfo, m_CommandBuffers.data()); + if(res != VK_SUCCESS){ + ConsoleLogError("vkAllocateCommandBuffers error because was unsuccessful in VulkanCommandBuffer.cpp: VulkanCommandBuffer::VulkanCommandBuffer()!"); + ConsoleLogError("Errored message is\t\t{}", VkResultToString(allocateResult)); + } + + ConsoleLogInfo("VulkanCmdBuffer initiated!"); + } + + VulkanCommandBuffer::~VulkanCommandBuffer(){ + } + + + /** + vk::record(commandBuffer, flags, [](){ + // do stuff... + }); + + + static void record(VulkanCommandBuffer, flags, UCommand cmd){ + commandBuffer.begin(flags); + cmd(); + commandBuffer.end(); + } + + @note Option #1 -- If there are multiple command buffers this is what it would look like: + + for(int i = 0; i < m_CommandBuffers.size(); i++){ + vk::record(m_CommandBuffers[i], flags, [](){ + + }); + } + + @note Option #2 + @note Esentially this will record commands to this buffer - that also depends how many command buffers is stored here. + vk::record(m_CommandBuffers, flags, [](){}); + + @note Backend would look + void record(m_CommandBuffers, flags, UCommand command){ + for(int i = 0; i < size; i++){ + auto& currCmdBuffer = m_CommandBuffers[i]; + currCmdBuffer.begin(flags); + command(); + currCmdBuffer.end(); + } + } + + */ + + VkCommandBuffer& VulkanCommandBuffer::GetActiveBuffer(uint32_t idx) { + return m_CommandBuffers[idx]; + } + + uint32_t VulkanCommandBuffer::Size() const{ + return m_CommandBuffers.size(); + } + + + + + + + + // void VulkanCommandBuffer::RecordClearBackgroundColor(float r, float g, float b, float a){ + // VkClearColorValue clearColorValue = { r, g, b, a}; + + // VkImageSubresourceRange imgRange = { + // .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + // .baseMipLevel = 0, + // .levelCount = 1, + // .baseArrayLayer = 0, + // .layerCount = 1 + // }; + + // uint32_t presentQueueFamily = VulkanDevice::GetLogicalDevice().QueueFamily(); + + // //! @param TODO -- Should fix the way we handle command buffers... am not liking this API! + // //! @note Used for recording the clear instructions before submission. + // for(uint32_t i = 0; i < m_CommandBuffers.size(); i++){ + // //! @param VK_IMAGE_LAYOUT_GENERAL layouts specify the pixels packed together inside actual memory of the image. + // //! @note Use of different layouts are for performance, whereas your GPU may perform better utilizing different layouts at diff stages of pipeline. + // //! @param VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT is used to make the state of this recorded buffer as a simultaneously use bit + // // Begin(m_CommandBuffers[i], VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT); + + // vkCmdClearColorImage(m_CommandBuffers[i], VulkanSwapchain::GetImage(i), VK_IMAGE_LAYOUT_GENERAL, &clearColorValue, 1, &imgRange); + // End(m_CommandBuffers[i]); + // } + + // ConsoleLogInfo("VulkanCommandBuffer::Record() called!"); + // } +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.cpp new file mode 100644 index 0000000..6f6a65a --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanCommandQueue.cpp @@ -0,0 +1,181 @@ +#include "Core/backend/utilities/helper_functions.h" +#include +#include +#include +#include +#include + +namespace engine3d::vk{ + + //! @note Helper functions for creating the semaphores + //! @note TODO --- Should change the way this works (?) + static VkSemaphore make_semaphore(VkDevice device){ + //! @note For semaphores we need specify what attributes the sempahores will have enabled + VkSemaphoreCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = nullptr, + .flags = 0 + }; + + //! @note Instantiating our sempahore handler + VkSemaphore semaphore; + VkResult res = vkCreateSemaphore(device, &createInfo, nullptr, &semaphore); + + //! @note Then validating if the creation of the semaphore object was valid. + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateSemaphore error message is {}", VkResultToString(res)); + } + + return semaphore; + } + + static VkFence make_fence(VkDevice device){ + VkFence fence; + VkFenceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + + VkResult res = vkCreateFence(device, &createInfo, nullptr, &fence); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateFence errored message was\t\t{}", VkResultToString(res)); + } + + return fence; + } + + VulkanCommandQueue::VulkanCommandQueue(uint32_t queueIdx){ + //! @note Fetching the queue's handler + vkGetDeviceQueue(VulkanDevice::GetVkLogicalDeviceInstance(), VulkanDevice::GetLogicalDevice().QueueFamily(), queueIdx, &m_CmdQueue); + + //! @note Added fence information in replacement of vkWaitIdle + VkFenceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = VK_FENCE_CREATE_SIGNALED_BIT + }; + + VkResult res = vkCreateFence(VulkanDevice::GetVkLogicalDeviceInstance(), &createInfo, nullptr, &m_RenderFence); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateFence errored message presented was\t\t{}", VkResultToString(res)); + return; + } + + ConsoleLogInfo("Queue Initiated!"); + + //! @note Creating semaphores + m_RenderCompleteSemaphore = make_semaphore(VulkanDevice::GetVkLogicalDeviceInstance()); + m_PresentCompleteSemaphore = make_semaphore(VulkanDevice::GetVkLogicalDeviceInstance()); + + m_RenderCompleteFence = make_fence(VulkanDevice::GetVkLogicalDeviceInstance()); + // m_PresentCompleteFence = make_fence(VulkanDevice::GetVkLogicalDeviceInstance()); + } + + //! @note This function returns the index of our image. Getting our next image. + uint32_t VulkanCommandQueue::AcquireNextImage(){ + uint32_t imageIdx = 0; + VkResult res = vkAcquireNextImageKHR(VulkanDevice::GetVkLogicalDeviceInstance(), VulkanSwapchain::GetVkSwapchainInstance(), std::numeric_limits::max(), m_PresentCompleteSemaphore, nullptr, &imageIdx); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkAcquireNextImageKHR error message {}", VkResultToString(res)); + } + + return imageIdx; + } + + VkQueue& VulkanCommandQueue::GetVkQueueInstance(){ + return m_CmdQueue; + } + + // void VulkanCommandQueue::ResetCommandBufferToEnqueue(){ + + // } + + void VulkanCommandQueue::SubmitAsync(VkCommandBuffer buffer){ + + //! @note Setting up our pipeline flags + //! @note Setting up our submission flag info. + //! @param VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT means to wait for clearing the window + VkPipelineStageFlags waitFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + + VkSubmitInfo submissionInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &m_PresentCompleteSemaphore, + .pWaitDstStageMask = &waitFlags, + .commandBufferCount = 1, + .pCommandBuffers = &buffer, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &m_RenderCompleteSemaphore + }; + + VkResult res = vkQueueSubmit(m_CmdQueue, 1, &submissionInfo, m_RenderCompleteFence); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkQueueSubmit submission ERROR message = {}", VkResultToString(res)); + } + } + + void VulkanCommandQueue::SubmitSync(VkCommandBuffer buffer){ + + VkSubmitInfo submissionInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = 1, + .pWaitSemaphores = VK_NULL_HANDLE, + .pWaitDstStageMask = VK_NULL_HANDLE, + .commandBufferCount = 1, + .pCommandBuffers = &buffer, + .signalSemaphoreCount = 0, + .pSignalSemaphores = VK_NULL_HANDLE + }; + + VkResult res = vkQueueSubmit(m_CmdQueue, 1, &submissionInfo, nullptr); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkQueueSubmit submission ERROR message = {}", VkResultToString(res)); + } + } + + //! @note function to present our data to the display + //! @note TODO -- Have an abstraction away from VulkanCommandQueue to VulkanPresentation. + void VulkanCommandQueue::Presentation(uint32_t imgIdx){ + VkPresentInfoKHR presentInfo = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + .waitSemaphoreCount = 1, // (1) waiting for semaphores to finish before starting presenting the next image + .pWaitSemaphores = &m_RenderCompleteSemaphore, // (2) waiting for semaphores to finish before starting presenting the next image + .swapchainCount = 1, // number of swapchains + .pSwapchains = &VulkanSwapchain::GetVkSwapchainInstance(), + .pImageIndices = &imgIdx // number of image that we want to present + }; + + VkResult res = vkQueuePresentKHR(m_CmdQueue, &presentInfo); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkQueuePresentKHR errored message = {}", VkResultToString(res)); + } + } + + void VulkanCommandQueue::WaitIdle(){ + vkQueueWaitIdle(m_CmdQueue); + } + + void VulkanCommandQueue::WaitIdleFence(){ + // vkResetCommandBuffer + + //! @note Since we applied the VkFence when we submit our command buffers. We need to specify when to wait until that command buffer has been rendered completely + vkWaitForFences(VulkanDevice::GetVkLogicalDeviceInstance(), 1, &m_RenderCompleteFence, true, 1000000); + vkResetFences(VulkanDevice::GetVkLogicalDeviceInstance(), 1, &m_RenderCompleteFence); + + // vkWaitForFences(VulkanDevice::GetVkLogicalDeviceInstance(), 1, &m_PresentCompleteFence, true, 1000000); + // vkResetFences(VulkanDevice::GetVkLogicalDeviceInstance(), 1, &m_PresentCompleteFence); + + + } + +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.cpp new file mode 100644 index 0000000..71464cf --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanDevice.cpp @@ -0,0 +1,305 @@ +#include +#include +#include +#include + +#define VK_USE_PLATFORM_WIN32_KHR +#define GLFW_INCLUDE_VULKAN +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#include + +namespace engine3d::vk{ + static VulkanPhysicalDevice g_PhysicalDevice; + static VulkanLogicalDevice g_LogicalDevice; + + /** + * @note The process that i learned when trying to check if physical devices are available is first check based on the size count of the devices. + * @note Then set the data to receive those properties to nullptr. + * @note Once verified that we have the physical device properties available, then we set that same parameter from nullptr to our actual data receivers from these functions + * @note When looking into this function, you'll see lots of repeats because they have to validate if there are those properties before uses. + */ + void VulkanPhysicalDevice::InitializePhysicalDevice(){ + //! @note Initializing Physical Device + uint32_t devicesCount = 0; + VkResult res = vkEnumeratePhysicalDevices(VulkanPipeline::GetVkInstance(), &devicesCount, nullptr); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkEnumeratePhysicalDevices Error (1) = {}", VkResultToString(res)); + } + + m_PhysicalDevices.resize(devicesCount); + + std::vector devices; + devices.resize(devicesCount); + + // VkResult r = vkEnumeratePhysicalDevices(g_physicalDevices.device, &devicesCount, m_PhysicalDevices.data()); + res = vkEnumeratePhysicalDevices(VulkanPipeline::GetVkInstance(), &devicesCount, devices.data()); + if(res != VK_SUCCESS){ + ConsoleLogError("vkEnumeratePhysicalDevices Error (2) = {}", VkResultToString(res)); + } + + /** + * @note First time we iterate we handle our physical device (that is our handler) + * @note Then once we specify that, the second time we actually try to get the queue families that are available on our system. + */ + for(uint32_t i = 0; i < devicesCount; i++){ + VkPhysicalDevice dev = devices[i]; + m_PhysicalDevices[i].device = dev; + vkGetPhysicalDeviceProperties(m_PhysicalDevices[i].device, &m_PhysicalDevices[i].deviceProperties); + + uint32_t apiVer = m_PhysicalDevices[i].deviceProperties.apiVersion; + uint32_t numQFamilies = 0; + + //! @note What first sets our physical device handler + vkGetPhysicalDeviceQueueFamilyProperties(dev, &numQFamilies, nullptr); + + #ifdef ENGINE_DEBUG_BUILD + ConsoleLogInfo("Device Name {}", m_PhysicalDevices[i].deviceProperties.deviceName); + ConsoleLogInfo("API Version: {}.{}.{}.{}", VK_API_VERSION_VARIANT(apiVer), VK_API_VERSION_MAJOR(apiVer), VK_API_VERSION_MINOR(apiVer), VK_API_VERSION_PATCH(apiVer)); + ConsoleLogInfo("Count of Family Queues: {}", numQFamilies); + #endif + + m_PhysicalDevices[i].queueFamProperties.resize(numQFamilies); + m_PhysicalDevices[i].queueSupportPresent.resize(numQFamilies); + + //! @note Since in the GPU draw instructions are represented in queues + //! @note Where there are different types of queue families that are specific to their respective use-cases. + //! @note Physical Device is used to expose what queue family do we want to submit our command buffers to. + //! @note What actually gives us our family properties + vkGetPhysicalDeviceQueueFamilyProperties(dev, &numQFamilies, m_PhysicalDevices[i].queueFamProperties.data()); + + // ============================================================================ + // ============================================================================ + // ============================================================================ + // ============================================================================ + for(uint32_t q = 0; q < numQFamilies; q++){ + const VkQueueFamilyProperties& qFamProperties = m_PhysicalDevices[i].queueFamProperties[q]; + VkQueueFlags flags = qFamProperties.queueFlags; + + res = vkGetPhysicalDeviceSurfaceSupportKHR(dev, q, VulkanPipeline::GetVkSurface(), &(m_PhysicalDevices[i].queueSupportPresent[q])); + #ifdef ENGINE_DEBUG_BUILD + ConsoleLogInfo("\t\tFamiy {} Num Queues: {} ", q, qFamProperties.queueCount); + ConsoleLogInfo("\t\tGFX {}, Compute {}, Transfer {}, Sparse Binding {}", (flags & VK_QUEUE_GRAPHICS_BIT) ? "Yes" : "No", (flags & VK_QUEUE_COMPUTE_BIT) ? "Yes" : "No", (flags & VK_QUEUE_TRANSFER_BIT) ? "Yes" : "No", (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? "Yes" : "No"); + if(res != VK_SUCCESS){ + ConsoleLogError("vkGetPhysicalDeviceSurfaceSupporKHR Error = {}", VkResultToString(res)); + } + #endif + } + + uint32_t formatsCount = 0; // NumFormats + res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, VulkanPipeline::VulkanPipeline::GetVkSurface(), &formatsCount, nullptr); + if(res != VK_SUCCESS){ + ConsoleLogError("vkGetPhysicalDeviceSurfaceFormatsKHR (1) Error = {}", VkResultToString(res)); + } + + m_PhysicalDevices[i].surfaceFormats.resize(formatsCount); + + res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, VulkanPipeline::VulkanPipeline::GetVkSurface(), &formatsCount, m_PhysicalDevices[i].surfaceFormats.data()); + if(res != VK_SUCCESS){ + ConsoleLogError("vkGetPhysicalDeviceSurfaceFormatsKHR (2) Error = {}", VkResultToString(res)); + } + + #ifdef ENGINE_DEBUG_BUILD + for(uint32_t j = 0; j < formatsCount; j++){ + const VkSurfaceFormatKHR& surfaceFormat = m_PhysicalDevices[i].surfaceFormats[j]; + ConsoleLogInfo("\t\tFormat {} color space {}", VkFormatToString(surfaceFormat.format), VkColorspaceToString(surfaceFormat.colorSpace)); + } + #endif + + res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, VulkanPipeline::VulkanPipeline::GetVkSurface(), &(m_PhysicalDevices[i].surfaceCapabilities)); + if(res != VK_SUCCESS){ + ConsoleLogInfo("vkGetPhysicalDeviceSurfaceCapabilitiesKHR Error = {}", VkResultToString(res)); + } + // else{ + // ConsoleLogInfo("Image Usage Flag {}", VkImageUsageFlagsToString(m_PhysicalDevices[i].surfaceCapabilities.supportedUsageFlags)); + // } + + uint32_t presentModesCount = 0; + res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, VulkanPipeline::VulkanPipeline::GetVkSurface(), &presentModesCount, nullptr); + + if(res != VK_SUCCESS){ + ConsoleLogInfo("vkGetPhysicalDeviceSurfacePresentModesKHR (1) Error = {}", VkResultToString(res)); + } + + res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, VulkanPipeline::VulkanPipeline::GetVkSurface(), &presentModesCount, m_PhysicalDevices[i].presentModes.data()); + if(res != VK_SUCCESS){ + ConsoleLogInfo("vkGetPhysicalDeviceSurfacePresentModesKHR (2) Error = {}", VkResultToString(res)); + } + + #ifdef ENGINE_DEBUG_BUILD + ConsoleLogInfo("Number of Presentation Modes {}", presentModesCount); + + vkGetPhysicalDeviceMemoryProperties(dev, &(m_PhysicalDevices[i].memoryProperties)); + ConsoleLogInfo("Number memory types {}", m_PhysicalDevices[i].memoryProperties.memoryTypeCount); + + for(uint32_t j = 0; j < m_PhysicalDevices[i].memoryProperties.memoryTypeCount; j++){ + ConsoleLogInfo("{}: flags, {}: Heap Index{} ", j, VkMemoryPropertyFlagToString(m_PhysicalDevices[i].memoryProperties.memoryTypes[i].propertyFlags), m_PhysicalDevices[i].memoryProperties.memoryTypes[i].heapIndex); + } + + ConsoleLogInfo("Num heap types {}", m_PhysicalDevices[i].memoryProperties.memoryHeapCount); + #endif + vkGetPhysicalDeviceFeatures(m_PhysicalDevices[i].device, &m_PhysicalDevices[i].phsicalDeviceFeatures); + } + } + + void VulkanPhysicalDevice::CleanupPhysicalDevice(){ + + } + + uint32_t VulkanPhysicalDevice::SelectDevice(VkQueueFlags ReqQueueFlag_t, bool IsSupportPresent){ + //! @note Going through all of our queue family of physical devices + //! @note Getting our properties of each families and check if the required type bitfields are required + //! @note Including if these requirements support presentation and if they are valid we return the queue family and keeping track of our current index. + for(uint32_t i = 0; i < m_PhysicalDevices.size(); i++){ + for(uint32_t j = 0; j < m_PhysicalDevices[i].queueFamProperties.size(); j++){ + const VkQueueFamilyProperties qFamProperties = m_PhysicalDevices[i].queueFamProperties[j]; + + if((qFamProperties.queueFlags & ReqQueueFlag_t) and ((bool)m_PhysicalDevices[i].queueSupportPresent[j] == IsSupportPresent)){ + m_DeviceIdx = i; + int queueFam = j; + // ConsoleLogInfo("Using GFX Device {} and Queue Family {}", m_DeviceIdx, queueFam); + return queueFam; // queue family tells us if our device supports the following flag bits (go to the definition to see what's supported) + } + } + } + + // ConsoleLogError("Required queue type {} and supports present {} was not found!", ReqQueueFlag_t, IsSupportPresent); + return 0; + } + + VkPhysicalDevice VulkanPhysicalDevice::Selected(){ + if(m_DeviceIdx < 0){ + ConsoleLogError("Physical device not selected!"); + } + + return m_PhysicalDevices[m_DeviceIdx].device; + } + + PhysicalDeviceAttribute VulkanPhysicalDevice::SelectedDevice(){ + if(m_DeviceIdx < 0){ + ConsoleLogError("Physical device not selected!"); + } + + return m_PhysicalDevices[m_DeviceIdx]; + } + + VkBool32 VulkanPhysicalDevice::IsGeometryShaderSupported(){ + return SelectedDevice().phsicalDeviceFeatures.geometryShader; + } + + VkBool32 VulkanPhysicalDevice::IsTesselationSupported(){ + return SelectedDevice().phsicalDeviceFeatures.tessellationShader; + } + + VkSurfaceCapabilitiesKHR VulkanPhysicalDevice::SurfaceCapabilities(){ return SelectedDevice().surfaceCapabilities; } + + std::vector VulkanPhysicalDevice::PresentationModes(){ return SelectedDevice().presentModes; } + + std::vector VulkanPhysicalDevice::SurfaceFormats(){ return SelectedDevice().surfaceFormats; } + + VkSurfaceCapabilitiesKHR VulkanPhysicalDevice::GetSurfaceCapabilities(){ + return g_PhysicalDevice.SurfaceCapabilities(); + } + + std::vector VulkanPhysicalDevice::GetSurfaceFormats(){ return g_PhysicalDevice.SurfaceFormats(); } + + std::vector VulkanPhysicalDevice::GetPresentationModes(){ + return g_PhysicalDevice.PresentationModes(); + } + + + + + void VulkanLogicalDevice::InitializeLogicalDevice(){ + g_PhysicalDevice.InitializePhysicalDevice(); + //! @note Selecting our graphics device and enable our presentation mode. + m_queueFamily = g_PhysicalDevice.SelectDevice(VK_QUEUE_GRAPHICS_BIT, true); + + float qPriorities[] = {1.0f}; + + //! @note Each device queue family create info references to a single queue family. + VkDeviceQueueCreateInfo qInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = m_queueFamily, // queue family index per family + .queueCount = 1, // num of queues from queue family + .pQueuePriorities = &qPriorities[0] // foreach queue of priorities from 1.0 to 0.0 + }; + + //! @note Initiating Physical device data attributes + std::vector deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME + }; + + VkPhysicalDeviceFeatures physicalDevFeatures = {0}; + physicalDevFeatures.geometryShader = VK_TRUE; + physicalDevFeatures.tessellationShader = VK_TRUE; + + VkDeviceCreateInfo deviceCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &qInfo, + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = (uint32_t)deviceExtensions.size(), + .ppEnabledExtensionNames = deviceExtensions.data(), + .pEnabledFeatures = &physicalDevFeatures + }; + + //! @note Checking if our physical device supports geometry/tesselation shaders + if(!g_PhysicalDevice.IsGeometryShaderSupported()){ + ConsoleLogError("Geometry Shader not supported!"); + } + + if(!g_PhysicalDevice.IsTesselationSupported()){ + ConsoleLogError("Tesselelation Shader not supported!"); + } + + VkResult res = vkCreateDevice(g_PhysicalDevice.Selected(), &deviceCreateInfo, nullptr, &m_Device); + + #ifdef ENGINE_DEBUG_BUILD + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateDevice Error in VulkanDevice::InitializeDevice()!"); + } + #endif + } + + void VulkanLogicalDevice::CleanupLogicalDevice(){ + } + + VkDevice VulkanLogicalDevice::LogicalDeviceInstance(){ return m_Device; } + + uint32_t& VulkanLogicalDevice::QueueFamily(){ return m_queueFamily; } + + void VulkanDevice::InitializeDevice(){ + g_LogicalDevice.InitializeLogicalDevice(); + } + + void VulkanDevice::CleanupDevice(){ + g_LogicalDevice.CleanupLogicalDevice(); + } + + VkPhysicalDevice VulkanDevice::GetVkPhysicalDeviceInstance(){ + return g_PhysicalDevice.Selected(); + } + + VkDevice VulkanDevice::GetVkLogicalDeviceInstance(){ + return g_LogicalDevice.LogicalDeviceInstance(); + } + + VulkanPhysicalDevice VulkanDevice::GetPhysicalDevice() { + return g_PhysicalDevice; + } + + VulkanLogicalDevice VulkanDevice::GetLogicalDevice() { + return g_LogicalDevice; + } + +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanPresentation.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanPresentation.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.cpp new file mode 100644 index 0000000..89cee93 --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanRenderPass.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace engine3d::vk{ + + struct VulkanRenderPassDescriptors{ + VkRenderPassBeginInfo renderPassBeginInfo; + VkAttachmentDescription attachmentDescription; + VkAttachmentReference color_attachment_ref; + }; + + static VulkanRenderPassDescriptors g_Descriptors; + + VulkanRenderPass::VulkanRenderPass(const std::string& debugName){ + + g_Descriptors.attachmentDescription = { + .flags = 0, + //! @note render pass uses this format + //! @note attachment will have format req by swapchain + .format = SelectSurfaceFormatAndColorspace(VulkanPhysicalDevice::GetSurfaceFormats()).format, + //! @note sample 1-bit, wont be using MSAA + .samples = VK_SAMPLE_COUNT_1_BIT, // used for multisampling + //! @note clear when attachment's loaded + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + //! @note keeping attachmentt stored when render pass ends + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + //! @note not going to be doing stencil for rn. + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + //! @note not using initial layout of attachment for rn + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + //! @note after render pass ends, image has to be on layour ready to be displayed. + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + }; + + g_Descriptors.color_attachment_ref = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + }; + + VkSubpassDescription subpass_desc = { + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = nullptr, + .colorAttachmentCount = 1, + .pColorAttachments = &g_Descriptors.color_attachment_ref, + .pResolveAttachments = nullptr, + .pDepthStencilAttachment = nullptr, + .preserveAttachmentCount = 0, + .pPreserveAttachments = nullptr + }; + + //! @note Setting up our resources for our attachments, dependencies, and how many subpasses are there for this specific render pass. + VkRenderPassCreateInfo renderPassCreateInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .attachmentCount = 1, + .pAttachments = &g_Descriptors.attachmentDescription, + .subpassCount = 1, + .pSubpasses = &subpass_desc, + .dependencyCount = 0, + .pDependencies = nullptr + }; + + VkResult res = vkCreateRenderPass(VulkanDevice::GetVkLogicalDeviceInstance(), &renderPassCreateInfo, nullptr, &m_RenderPass); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateRenderPass errored out! Error message is\t\t{}", VkResultToString(res)); + } + + //! @note RenderpassesBeginInfo is like equivalent to setting up configurations of the this specific render pass + //! @note Meaning instead of setting the clear color and recording it. This descriptor begin info already records our clear color. + g_Descriptors.renderPassBeginInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .pNext = nullptr, + .renderPass = m_RenderPass, + .renderArea = { + .offset = { + .x = 0, + .y = 0 + }, + .extent = { + .width = VulkanPipeline::GetWidth(), + .height = VulkanPipeline::GetHeight() + }, + }, + .clearValueCount = 1, + .pClearValues = Renderer::GetClearColor() // This is how we set our color to our window without actually doing our recording. + }; + + ConsoleLogInfo("VulkanRenderPass Initiated!"); + ConsoleLogInfo("VulkanRendererPass Debug Name === {}", debugName); + + //! @note Initializing framebuffers + m_Framebuffers.resize(VulkanSwapchain::GetImagesSize()); + + for(uint32_t i = 0; i < VulkanSwapchain::GetImagesSize(); i++){ + VkFramebufferCreateInfo fbCreateInfo = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = m_RenderPass, + .attachmentCount = 1, + .pAttachments = &VulkanSwapchain::GetImageView(i), + .width = VulkanPipeline::GetWidth(), + .height = VulkanPipeline::GetHeight(), + .layers = 1 + }; + + VkResult fbRes = vkCreateFramebuffer(VulkanDevice::GetVkLogicalDeviceInstance(), &fbCreateInfo, nullptr, &m_Framebuffers[i]); + + if(fbRes != VK_SUCCESS){ + ConsoleLogError("Framebuffer at index ({}) errored out! Error message is\t\t{}", i, VkResultToString(fbRes)); + } + } + + ConsoleLogInfo("Framebuffers also created after render pass!"); + } + + void VulkanRenderPass::Begin(VkCommandBuffer buffer, VkSubpassContents contents){ + if(m_RenderPass == nullptr){ + ConsoleLogError("This could mean m_RenderPass was in fact nullptr!"); + } + vkCmdBeginRenderPass(buffer, &g_Descriptors.renderPassBeginInfo, contents); + } + + void VulkanRenderPass::End(VkCommandBuffer buffer){ + if(m_RenderPass == nullptr){ + ConsoleLogError("This could mean m_RenderPass was in fact nullptr!"); + } + vkCmdEndRenderPass(buffer); + } + + void VulkanRenderPass::SetCurrentFramebuffer(uint32_t idx){ + g_Descriptors.renderPassBeginInfo.framebuffer = m_Framebuffers[idx]; + } + + VkRenderPassBeginInfo& VulkanRenderPass::GetBeginInfo(){ return g_Descriptors.renderPassBeginInfo; } + + + VkFramebuffer& VulkanRenderPass::GetFramebuffer(uint32_t idx){ + return m_Framebuffers[idx]; + } + + VkRenderPass& VulkanRenderPass::GetVkRenderPass(){ return m_RenderPass; } +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.cpp new file mode 100644 index 0000000..6640205 --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/VulkanSwapchain.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace engine3d::vk{ + static VkSwapchainKHR g_Swapchain; + static std::vector g_Images; // images stored in this swapchain that can be used during presentation mode + static std::vector g_ImageViews; // In vulkan we cant access directly to images, instead we need to create image views to access our images in our swapchain. Gives access to subset of our images + + static VkPresentModeKHR SelectPresentMode(const std::vector& presentationModes){ + for(int i = 0; i < presentationModes.size(); i++){ + if(presentationModes[i] == VK_PRESENT_MODE_MAILBOX_KHR){ + return presentationModes[i]; + } + } + + //! @note Fallback to FIFO which is always supported + return VK_PRESENT_MODE_FIFO_KHR; + } + + static uint32_t SelectSizeofImages(const VkSurfaceCapabilitiesKHR& capabilities){ + uint32_t requestedImagesCount = capabilities.minImageCount + 1; + + int finalImagesCount = 0; + + if((capabilities.maxImageCount > 0) and (requestedImagesCount > capabilities.maxImageCount)){ + finalImagesCount = capabilities.maxImageCount; + } + else{ + finalImagesCount = requestedImagesCount; + } + + return finalImagesCount; + } + + //! @note Helper function to create an image view + //! @note Wrapper helper function that includes the creation of the vkCreateImageView function! + static VkImageView CreateImageView(VkImage img, VkFormat format, VkImageAspectFlags aspectFlags, VkImageViewType view_t, uint32_t layerCount, uint32_t mipLevels){ + VkImageViewCreateInfo viewInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = img, + .viewType = view_t, + .format = format, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY + }, + .subresourceRange = { + .aspectMask = aspectFlags, + .baseMipLevel = 0, + .levelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = layerCount + }, + }; + + VkImageView imageView; + VkResult res = vkCreateImageView(VulkanDevice::GetVkLogicalDeviceInstance(), &viewInfo, nullptr, &imageView); + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateImageView\t\tErrored creating an image view"); + } + + return imageView; + } + + VulkanSwapchain::~VulkanSwapchain(){ + for(int i = 0; i < g_Images.size(); i++){ + vkDestroyImageView(VulkanDevice::GetVkLogicalDeviceInstance(), g_ImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(VulkanDevice::GetVkLogicalDeviceInstance(),g_Swapchain, nullptr); + vkDestroyDevice(VulkanDevice::GetVkLogicalDeviceInstance(),nullptr); + + //! @note TODO -- Move this in either Vulkan.h or VulkanDevice.h that handles VkSurfaceKHR + // PFN_vkDestroySurfaceKHR vkDestroySurface = VK_NULL_HANDLE; + // vkDestroySurface = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(VulkanPipeline::GetVkInstance(), "vkDestroySurfaceKHR"); + + // if(!vkDestroySurface){ + // ConsoleLogError("Cannot find address for vkDestroyDebugUtilsMesenger!"); + // exit(1); + // } + } + + void VulkanSwapchain::InitializeSwaphchain(){ + const VkSurfaceCapabilitiesKHR surfaceCap = VulkanPhysicalDevice::GetSurfaceCapabilities(); + uint32_t imagesCount = SelectSizeofImages(surfaceCap); + + VkPresentModeKHR presentationModes = SelectPresentMode(VulkanPhysicalDevice::GetPresentationModes()); + VkSurfaceFormatKHR surfaceFormat = SelectSurfaceFormatAndColorspace(VulkanPhysicalDevice::GetSurfaceFormats()); + + VkSwapchainCreateInfoKHR swapchainCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .surface = VulkanPipeline::GetVkSurface(), + .minImageCount = imagesCount, + .imageFormat = surfaceFormat.format, + .imageColorSpace = surfaceFormat.colorSpace, + .imageExtent = surfaceCap.currentExtent, // currentExtent is the extent of the window + .imageArrayLayers = 1, // relevelant to stereoscoptic surface + .imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), // refer the usage of the images + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, // exclusive sharing mode just means that only one queue family can use it as a time. + .queueFamilyIndexCount = 1, + .pQueueFamilyIndices = &VulkanDevice::GetLogicalDevice().QueueFamily(), + .preTransform = surfaceCap.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = presentationModes, + .clipped = true, + }; + + VkResult res = vkCreateSwapchainKHR(VulkanDevice::GetVkLogicalDeviceInstance(), &swapchainCreateInfo, nullptr, &g_Swapchain); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkCreateSwapchainKHR error, was unsuccessful! Error message is\t\t{}", VkResultToString(res)); + } + // else{ + // ConsoleLogInfo("vkCreateSwapchainKHR was created successful!"); + // } + + uint32_t swapchainImagesCount = 0; + res = vkGetSwapchainImagesKHR(VulkanDevice::GetVkLogicalDeviceInstance(), g_Swapchain, &swapchainImagesCount, nullptr); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkGetSwapchainImagesKHR Error (1) with errored message\t\t{}", VkResultToString(res)); + } + // else{ + // ConsoleLogInfo("Swapchain\t\tNumber of Images {}", swapchainImagesCount); + // } + + g_Images.resize(swapchainImagesCount); + g_ImageViews.resize(swapchainImagesCount); + + //! @note Getting all of the handles for our images + res = vkGetSwapchainImagesKHR(VulkanDevice::GetVkLogicalDeviceInstance(), g_Swapchain, &swapchainImagesCount, g_Images.data()); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkGetSwapchainImagesKHR Error (2) with errored message\t\t{}", VkResultToString(res)); + } + + int layerCount = 1; + int mipLevels = 1; + + for(uint32_t i = 0; i < swapchainImagesCount; i++){ + g_ImageViews[i] = CreateImageView(g_Images[i], surfaceFormat.format, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_VIEW_TYPE_2D, layerCount, mipLevels); + } + } + + VkSwapchainKHR& VulkanSwapchain::GetVkSwapchainInstance(){ + return g_Swapchain; + } + + VkImage& VulkanSwapchain::GetImage(uint32_t index){ + return g_Images[index]; + } + + VkImageView& VulkanSwapchain::GetImageView(uint32_t index){ + return g_ImageViews[index]; + } + + uint32_t VulkanSwapchain::GetImagesSize() { return g_Images.size(); } + +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.cpp b/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.cpp new file mode 100644 index 0000000..79b7c8f --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +namespace engine3d::vk{ + void begin(const VkCommandBuffer& buffer, VkCommandBufferUsageFlags p_UsageFlags){ + VkCommandBufferBeginInfo beginInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = p_UsageFlags, + .pInheritanceInfo = nullptr + }; + + VkResult res = vkBeginCommandBuffer(buffer, &beginInfo); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkBeginCommandBuffer errored message!===>\t\t\t{}", vk::VkResultToString(res)); + } + } + + void end(const VkCommandBuffer& buffer){ + VkResult res = vkEndCommandBuffer(buffer); + + if(res != VK_SUCCESS){ + ConsoleLogError("vkEndCommandBuffer errored message!===>\t\t\t{}", vk::VkResultToString(res)); + } + } +}; \ No newline at end of file diff --git a/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h b/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h new file mode 100644 index 0000000..e2882a0 --- /dev/null +++ b/src/engine3d/Core/backend/Vulkan-Experiemental/helper-functions.h @@ -0,0 +1,16 @@ +#pragma once + +namespace engine3d{ + namespace vk{ + class VulkanCommandBuffer; + + /** + * @name record + * @note Collects the command user supplies into the command buffer. + */ + template + void record(VulkanCommandBuffer& commandBuffer, const UCommand&& p_CommandToCollect){ + + } + }; +}; \ No newline at end of file diff --git a/test_package/Application-Old.cpp b/test_package/Application-Old.cpp new file mode 100644 index 0000000..4c25827 --- /dev/null +++ b/test_package/Application-Old.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include + +namespace engine3d{ + class TestApplication : public ApplicationInstance{ + public: + TestApplication(const std::string p_DebugName="TestApplication") : ApplicationInstance(p_DebugName) { + Renderer::Initialize(); + Renderer::SetBackgroundColor({0.0f, 0.5f, 0.5f, 0.f}); + } + + void UpdateThisApplicationInstance(){ + ConsoleLogInfo("Running application!"); + + //! @note Just testing to see if application still closes cleanly. + // if(InputPoll::IsKeyPressed(ENGINE_KEY_ESCAPE)){ + // exit(0); + // } + + //! @note This function will render our primitives + //! @note TODO -- Flush should only happens when our scene is given everything that lives within this scene (ref to lifetimes) + Renderer::FlushScene(); + + // ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + // ImGui::End(); + } + + }; + + ApplicationInstance* InitializeApplication(){ + return new TestApplication(); + } +}; \ No newline at end of file diff --git a/test_package/Application.cpp b/test_package/Application.cpp new file mode 100644 index 0000000..12240ec --- /dev/null +++ b/test_package/Application.cpp @@ -0,0 +1,30 @@ +#include "Application.h" +#include +#include "engine3d/Core/EngineLogger.h" +#include "engine3d/Core/Renderer/Renderer.h" +#include +#include + +namespace engine3d{ + + TestApplication::TestApplication(const std::string& p_DebugName) : ApplicationInstance(p_DebugName) { + Renderer::Initialize(); + Renderer::SetBackgroundColor({0.0f, 0.5f, 0.5f, 0.f}); + + ConsoleLogInfo("Initializing Current Application Name === {}!!!", ApplicationInstance::CurrentApplicationName()); + } + + TestApplication::~TestApplication() {} + + void TestApplication::UpdateThisApplicationInstance(){ + Renderer::RenderBasicClearColor(); + Renderer::Presentation(); + } + + ApplicationInstance* InitializeApplication(){ + return new TestApplication(); + } + + + +}; diff --git a/test_package/Application.h b/test_package/Application.h new file mode 100644 index 0000000..ca0f164 --- /dev/null +++ b/test_package/Application.h @@ -0,0 +1,23 @@ +#pragma once +#include + +namespace engine3d{ + + //! @note Our actual editor application + //! @note TODO -- Having a cenrtal application that will be used across both editor and the game(being developed) + //! @note So when they're packaged, they can be shipped under one application excluding editor stuff and only things relevant to the game. + class TestApplication : public ApplicationInstance{ + public: + TestApplication(const std::string& debugName = "Engine3D Editor"); + virtual ~TestApplication(); + private: + //! @note TODO -- Probably have a cleanup handler for this + //! @note Such as WorldCleanup() or some API to make sure we can cleanly deallocate and delete things... + // void ShutdownEditor(); + void UpdateThisApplicationInstance() override; + + private: + //! @note Editor application, Engine, UI Layer. + float m_LastFrameTime = 0.0f; + }; +}; \ No newline at end of file diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index e53ddaa..13058a0 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -1,15 +1,23 @@ cmake_minimum_required(VERSION 3.15) project(example CXX) +find_package(Vulkan REQUIRED) +find_package(imguidocking REQUIRED) find_package(engine3d CONFIG REQUIRED) -add_executable(example src/Application.cpp) +add_executable(example Application.h Application.cpp EngineLayer.h EngineLayer.cpp UILayer.h UILayer.cpp) -target_include_directories(${PROJECT_NAME} PUBLIC ../) +# set_target_properties( ${PROJECT_NAME} +# PROPERTIES +# ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" +# LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" +# RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/../" +# ) -# file(COPY Resources DESTINATION ${CMAKE_BINARY_DIR}) -# file(COPY Resources DESTINATION build PATTERN build EXCLUDE) - -target_link_libraries(${PROJECT_NAME} engine3d::engine3d) +target_link_libraries(${PROJECT_NAME} + Vulkan::Vulkan + imguidocking::imguidocking + engine3d::engine3d +) \ No newline at end of file diff --git a/test_package/EngineLayer.cpp b/test_package/EngineLayer.cpp new file mode 100644 index 0000000..bffb8fe --- /dev/null +++ b/test_package/EngineLayer.cpp @@ -0,0 +1,33 @@ +#include "EngineLayer.h" +#include +#include +#include + +namespace engine3d{ + EngineLayer::EngineLayer() : Layer("EngineLayer") {} + + void EngineLayer::BeginPlay(){ + ConsoleLogInfo("EngineLayer::BeginPlay function called in class {}", Layer::GetLayerString()); + } + + void EngineLayer::EndPlay(){ + // ConsoleLogInfo("EngineLayer::EndPlay function called"); + } + + void EngineLayer::UpdateFrame(float ts){ + // ConsoleLogInfo("EngineLayer::UpdateFrame(float) function called"); + if(InputPoll::IsKeyPressed(ENGINE_KEY_ESCAPE)){ + ConsoleLogError("IsKeyPressed pressed!"); + exit(0); + } + } + + // void EngineLayer::UpdateEvent(Event& event){ + // // ConsoleLogInfo("EngineLayer::UpdateEvent(Event&) function called"); + // } + + void EngineLayer::UpdateUI(){} + + + std::string EngineLayer::GetName() const { return Layer::GetLayerString(); } +}; \ No newline at end of file diff --git a/test_package/EngineLayer.h b/test_package/EngineLayer.h new file mode 100644 index 0000000..6b41a35 --- /dev/null +++ b/test_package/EngineLayer.h @@ -0,0 +1,20 @@ +#pragma once +#include + +namespace engine3d{ + //! @note THis is where we do our actual engine interactiveness for the editor here. + class EngineLayer : public Layer{ + public: + EngineLayer(); + //! @note To get our current world layer. + //! @note Abstracting where the user is trying to add widgets to the engine or their game. + //! @note EngineLayer ideally could be the actors known world view. + std::string GetName() const; + protected: + void BeginPlay() override; + void EndPlay() override; + void UpdateFrame(float ts) override; + // void UpdateEvent(Event& event) override; + void UpdateUI() override; + }; +}; \ No newline at end of file diff --git a/test_package/UILayer.cpp b/test_package/UILayer.cpp new file mode 100644 index 0000000..a2a8b83 --- /dev/null +++ b/test_package/UILayer.cpp @@ -0,0 +1,144 @@ +#include "UILayer.h" +#include "engine3d/Core/backend/Vulkan/VulkanDevice.h" +#include "engine3d/Core/backend/Vulkan/VulkanSwapchain.h" +// #include "engine3d/Core/backend/Vulkan/VulkanSwapchain.h" +#include +#include + +namespace engine3d{ + UILayer::UILayer() : Layer("UILayer") { + } + + void UILayer::InitializeUI(){ + // IMGUI_CHECKVERSION(); + // ImGui::CreateContext(); + // ImGuiIO& io = ImGui::GetIO(); (void)io; + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // ImGui::StyleColorsDark(); + + // Setup Dear ImGui style + // ImGui::StyleColorsDark(); + // // SetDarkThemeV2Colors(); + // // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. + // ImGuiStyle& style = ImGui::GetStyle(); + // if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + // { + // style.WindowRounding = 0.0f; + // style.Colors[ImGuiCol_WindowBg].w = 1.0f; + // } + // style.Colors[ImGuiCol_WindowBg] = ImVec4(0.15f, 0.15f, 0.15f, style.Colors[ImGuiCol_WindowBg].w); + + // ImGui_ImplGlfw_InitForVulkan(vk::VulkanPipeline::GetCurrentWindow(), true); + // ImGui_ImplVulkan_InitInfo init_info = {}; + // init_info.Instance = vk::VulkanPipeline::GetVkInstance(); + // init_info.PhysicalDevice = vk::VulkanDevice::GetVkPhysicalDeviceInstance(); + // init_info.Device = vk::VulkanDevice::GetVkLogicalDeviceInstance(); + // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); + // // init_info.Queue = g_Queue; + // init_info.Queue = queue, + // // init_info.PipelineCache = g_PipelineCache; + // init_info.PipelineCache = nullptr, + // // init_info.RenderPass = 1, + // // init_info.DescriptorPool = g_DescriptorPool; + // // init_info.RenderPass = wd->RenderPass; + // init_info.Subpass = 1; + // // init_info.MinImageCount = g_MinImageCount; + // init_info.MinImageCount = 0, + // // init_info.ImageCount = wd->ImageCount; + // // init_info.ImageCount = 1, + // init_info.ImageCount = vk::VulkanSwapchain::GetImagesSize(), + // init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + // // init_info.Allocator = g_Allocator; + // init_info.Allocator = nullptr, + // // init_info.CheckVkResultFn = check_vk_result; + + // // ImGui_ImplVulkan_Init(&init_info); + // ImGui_ImplVulkan_Init(&init_info, nullptr); + } + + void UILayer::BeginPlay(){ + ConsoleLogInfo("UILayer::BeginPlay function called in class {}", Layer::GetLayerString()); + // ImGui_ImplGlfw_NewFrame(); + // IMGUI_CHECKVERSION(); + // ImGui::CreateContext(); + // ImGuiIO& io = ImGui::GetIO(); (void)io; + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // // ImGui::StyleColorsDark(); + + // // Setup Dear ImGui style + // ImGui::StyleColorsDark(); + // // SetDarkThemeV2Colors(); + // // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. + // ImGuiStyle& style = ImGui::GetStyle(); + // if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + // { + // style.WindowRounding = 0.0f; + // style.Colors[ImGuiCol_WindowBg].w = 1.0f; + // } + // style.Colors[ImGuiCol_WindowBg] = ImVec4(0.15f, 0.15f, 0.15f, style.Colors[ImGuiCol_WindowBg].w); + + // ImGui_ImplGlfw_InitForVulkan(vk::VulkanPipeline::GetCurrentWindow(), true); + // ImGui_ImplVulkan_InitInfo init_info = {}; + // init_info.Instance = vk::VulkanPipeline::GetVkInstance(); + // init_info.PhysicalDevice = vk::VulkanDevice::GetVkPhysicalDeviceInstance(); + // init_info.Device = vk::VulkanDevice::GetVkLogicalDeviceInstance(); + // init_info.QueueFamily = vk::VulkanDevice::GetLogicalDevice().QueueFamilyVkCount(); + // // init_info.Queue = g_Queue; + // init_info.Queue = nullptr, + // // init_info.PipelineCache = g_PipelineCache; + // init_info.PipelineCache = nullptr, + // // init_info.RenderPass = 0, + // // init_info.DescriptorPool = g_DescriptorPool; + // // init_info.RenderPass = wd->RenderPass; + // init_info.Subpass = 0; + // // init_info.MinImageCount = g_MinImageCount; + // init_info.MinImageCount = 0, + // // init_info.ImageCount = wd->ImageCount; + // init_info.ImageCount = 1, + // init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + // // init_info.Allocator = g_Allocator; + // init_info.Allocator = nullptr, + // // init_info.CheckVkResultFn = check_vk_result; + + // // ImGui_ImplVulkan_Init(&init_info); + // ImGui_ImplVulkan_Init(&init_info, nullptr); + + // ImGui_ImplVulkan_NewFrame(); + // ImGui_ImplGlfw_NewFrame(); + // ImGui::NewFrame(); + // ImGui_ImplGlfw_InitForVulkan(vk::VulkanPipeline::GetCurrentWindow(), false); + + // ImGui_ImplVulkan_NewFrame(); + // ImGui_ImplGlfw_NewFrame(); + // ImGui::NewFrame(); + } + + void UILayer::EndPlay(){ + // ConsoleLogInfo("UILayer::EndPlay function called in class {}", Layer::GetLayerString()); + // ImGui_ImplVulkan_Shutdown(); + // ImGui_ImplGlfw_Shutdown(); + // ImGui::DestroyContext(); + + // ImGui_ImplVulkan_Shutdown(); + // ImGui_ImplGlfw_Shutdown(); + // ImGui::DestroyContext(); + } + + void UILayer::UpdateFrame(float ts){ + // ImGui::Render(); + // ConsoleLogInfo("UILayer::UpdateFrame(float) function called in class {}", Layer::GetLayerString()); + } + + // void UILayer::UpdateEvent(Event& event){ + // // ConsoleLogInfo("UILayer::UpdateEvent(Event&) function called in class {}", Layer::GetLayerString()); + // } + + void UILayer::UpdateUI(){ + // ImGui::Begin("Settings"); + // ImGui::End(); + } + + std::string UILayer::GetName() const { return Layer::GetLayerString(); } +}; \ No newline at end of file diff --git a/test_package/UILayer.h b/test_package/UILayer.h new file mode 100644 index 0000000..6e7b01e --- /dev/null +++ b/test_package/UILayer.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace engine3d{ + class UILayer : public engine3d::Layer{ + public: + UILayer(); + + static void InitializeUI(); + + std::string GetName() const; + protected: + void BeginPlay() override; + void EndPlay() override; + void UpdateFrame(float ts) override; + // void UpdateEvent(Event& event) override; + void UpdateUI() override; + }; +}; \ No newline at end of file diff --git a/test_package/conanfile.py b/test_package/conanfile.py index ce53519..21299b3 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -10,6 +10,8 @@ class engine3dTestConan(ConanFile): generators = "CMakeDeps", "CMakeToolchain" def requirements(self): + # self.requires("engine3d/1.0") + self.requires("imguidocking/1.0") self.requires(self.tested_reference_str) def build(self): @@ -21,10 +23,7 @@ def layout(self): cmake_layout(self) # This is to run the example code - # Disabling it - # def test(self): def test(self): - pass - # if can_run(self): - # cmd = os.path.join(self.cpp.build.bindir, "example") - # self.run(cmd, env="conanrun") + if can_run(self): + cmd = os.path.join(self.cpp.build.bindir, "example") + self.run(cmd, env="conanrun") \ No newline at end of file diff --git a/test_package/src/Application.cpp b/test_package/src/Application.cpp deleted file mode 100644 index c8aa9f2..0000000 --- a/test_package/src/Application.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -extern void Engine3DInitializeCore(); - -int main(int argc, char** argv){ - Engine3DInitializeCore(); - ConsoleLogInfo("Test_Package initiated!"); - printf("Testing!\n"); -} \ No newline at end of file