diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 60aa3f0..ef35bb9 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -83,6 +83,7 @@ if (EDITOR_MODE) "src/Editor/EditorHelpers.h" "src/Editor/Editor.h" "src/Editor/Panels/SceneHierarchyPanel.h" + "src/Editor/Panels/ProfileTelemetryPanel.h" ) endif() @@ -93,6 +94,7 @@ set(ENGINE_SOURCES "src/Core/Log.cpp" "src/Core/Window.cpp" "src/Core/SettingsConfig.cpp" +"src/Core/Profiler.cpp" "src/Events/EventManager.cpp" "src/Renderer/Buffer.cpp" "src/Renderer/GraphicsContext.cpp" @@ -149,6 +151,7 @@ if (EDITOR_MODE) "src/Editor/EditorHelpers.cpp" "src/Editor/Editor.cpp" "src/Editor/Panels/SceneHierarchyPanel.cpp" + "src/Editor/Panels/ProfileTelemetryPanel.cpp" ) endif() diff --git a/Engine/src/Core/Application.cpp b/Engine/src/Core/Application.cpp index 8361dc1..657e374 100644 --- a/Engine/src/Core/Application.cpp +++ b/Engine/src/Core/Application.cpp @@ -2,6 +2,7 @@ #include "FileSystem.h" #include "Input.h" +#include "Profiler.h" #include "SettingsConfig.h" #include "Timer.h" #include "Window.h" @@ -106,61 +107,82 @@ void Application::Run() m_window->OnUpdate(); } - const float elapsedTime = timer.Elapsed(); + const float elapsedTimeMs = timer.ElapsedMs(); + const float elapsedTime = elapsedTimeMs * 0.001f; timer.Restart(); - if (timerFpsCounter.ElapsedMs() > 100.0f) { - s_telemetry.frameTime = elapsedTime * 1000.0f; + { + if (timerFpsCounter.ElapsedMs() > 100.0f) { + s_telemetry.frameTime = elapsedTimeMs; - s_telemetry.fps = 1.0f / elapsedTime; + s_telemetry.fps = 1.0f / elapsedTime; - timerFpsCounter.Restart(); - } + timerFpsCounter.Restart(); + } - if (gEngineSettings.enableFpsCounter) { - GetScene().GetComponent(m_fpsCounterEntityId).text - = fmt::format("{:0.3f} ms ({} fps)", s_telemetry.frameTime, static_cast(std::floor(s_telemetry.fps))); + if (gEngineSettings.enableFpsCounter) { + GetScene().GetComponent(m_fpsCounterEntityId).text + = fmt::format("{:0.3f} ms ({} fps)", s_telemetry.frameTime, static_cast(std::floor(s_telemetry.fps))); + } } // ============== Process input step ============== + { + PROFILE_SCOPE("Process input in: "); - if (m_cameraController) { - m_cameraController->OnProcessInput(elapsedTime); + if (m_cameraController) { + m_cameraController->OnProcessInput(elapsedTime); + } + OnProcessInput(elapsedTime); } - OnProcessInput(elapsedTime); // ============== Update step ============== - if (m_cameraController) { - m_cameraController->OnUpdate(elapsedTime); + { + PROFILE_SCOPE("Update input in: "); + if (m_cameraController) { + m_cameraController->OnUpdate(elapsedTime); + } + gMeshLibrary.Update(); + gTextureManager.Update(); + gSceneManager.Update(elapsedTime); + + OnUpdate(elapsedTime); } - gMeshLibrary.Update(); - gTextureManager.Update(); - gSceneManager.Update(elapsedTime); - OnUpdate(elapsedTime); + // ============== Dispatch queued events ============== + { + PROFILE_SCOPE("Dispatch events in: "); + events::gEventManager.DispatchEvents(); + } // ============== Rendering Step ============== - RenderCommand::SetClearColor(Renderer::GetClearColor()); - RenderCommand::Clear(); + { + PROFILE_SCOPE("Render in: "); + RenderCommand::SetClearColor(Renderer::GetClearColor()); + RenderCommand::Clear(); - gSceneManager.Render(elapsedTime); - OnRender(elapsedTime); + gSceneManager.Render(elapsedTime); + OnRender(elapsedTime); + } #if EDITOR_MODE - if (gEngineSettings.enableEditor) { - m_imGuiOverlay.Begin(); - m_editor.OnImGuiRender(); - OnImguiRender(); - m_imGuiOverlay.End(); + { + PROFILE_SCOPE("ImGui Render in: "); + if (gEngineSettings.enableEditor) { + m_imGuiOverlay.Begin(); + m_editor.OnImGuiRender(); + OnImguiRender(); + m_imGuiOverlay.End(); + } } #endif // ============== Window update step ============== - m_window->OnUpdate(); - - // ============== Dispatch queued events ============== - events::gEventManager.DispatchEvents(); + { + PROFILE_SCOPE("Update window in: "); + m_window->OnUpdate(); + } } } diff --git a/Engine/src/Core/Profiler.cpp b/Engine/src/Core/Profiler.cpp new file mode 100644 index 0000000..1c3c202 --- /dev/null +++ b/Engine/src/Core/Profiler.cpp @@ -0,0 +1,10 @@ +#pragma once + +#include "Profiler.h" + +namespace elv { +void ProfileTelemetry::Update(const std::string& name, const float value) +{ + m_telemetry[name] = value; +} +} // namespace elv diff --git a/Engine/src/Core/Profiler.h b/Engine/src/Core/Profiler.h index dc87553..84b9580 100644 --- a/Engine/src/Core/Profiler.h +++ b/Engine/src/Core/Profiler.h @@ -6,18 +6,44 @@ #include namespace elv { +class ProfileTelemetry { +public: + static ProfileTelemetry& GetInstance() + { + static ProfileTelemetry instance; + return instance; + } + + const std::unordered_map& GetTelemetry() const { return m_telemetry; } + + void Update(const std::string& name, const float value); + +private: + std::unordered_map m_telemetry; +}; + +extern ProfileTelemetry gProfileTelemetry; + class Profiler { public: - Profiler(const std::string& text) + Profiler(const std::string& text, const bool writeToLog = false) : m_text(text) + , m_writeToLog(writeToLog) { } ~Profiler() { - EL_INFO("{0} {1} ms.", m_text, m_timer.ElapsedMs()); + const float elapsed = m_timer.ElapsedMs(); + if (m_writeToLog) { + EL_INFO("{0} {1} ms.", m_text, elapsed); + + } else { + ProfileTelemetry::GetInstance().Update(m_text, elapsed); + } } private: + bool m_writeToLog { false }; std::string m_text; Timer m_timer; }; @@ -27,6 +53,8 @@ class Profiler { # define PROFILE_SCOPE(name) Profiler p(name); +# define PROFILE_TO_LOG(name) Profiler p(name, true); + #else # define PROFILE(...) # define PROFILE_SCOPE(...) diff --git a/Engine/src/Core/Timer.h b/Engine/src/Core/Timer.h index 951781c..8b95e73 100644 --- a/Engine/src/Core/Timer.h +++ b/Engine/src/Core/Timer.h @@ -18,8 +18,6 @@ class Timer { float Elapsed() const { return std::chrono::duration_cast(clock::now() - m_start).count(); } float ElapsedMs() const { return std::chrono::duration_cast(clock::now() - m_start).count(); } - // static long long GetTimeNow() { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } - private: using clock = std::chrono::high_resolution_clock; // QueryPerformanceCounter using seconds = std::chrono::duration>; @@ -28,4 +26,6 @@ class Timer { std::chrono::time_point m_start; }; +inline long long GetTimeNow() { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } + } // namespace elv diff --git a/Engine/src/Editor/Editor.cpp b/Engine/src/Editor/Editor.cpp index e69011d..fb59b24 100644 --- a/Engine/src/Editor/Editor.cpp +++ b/Engine/src/Editor/Editor.cpp @@ -7,7 +7,6 @@ #include "Core/Window.h" #include "Renderer/RenderCommand.h" #include "Renderer/Renderer.h" -#include "Renderer/Renderer2D.h" #include @@ -47,18 +46,6 @@ void Editor::OnImGuiRender() if (ImGui::Checkbox("MSAA", &m_isMSAAEnabled)) { RenderCommand::EnableMSAA(m_isMSAAEnabled); } - ImGui::Spacing(); - ImGui::Separator(); - - // telemetry - ImGui::Text("FPS: %.1f", Application::GetTelemetry().fps); - ImGui::Text("Frame time %.3f ms", Application::GetTelemetry().frameTime); - - ImGui::Separator(); - - ImGui::Text("2D renderer telemetry:"); - ImGui::Text(" draw calls: %i", Renderer2D::GetTelemetry().drawCalls); - ImGui::End(); // ============ Environment ============ @@ -73,5 +60,7 @@ void Editor::OnImGuiRender() if (gEngineSettings.enableSceneGraph) { m_sceneHierarchyPanel.OnImGuiRender(); } + + m_profileTelemetry.OnImGuiRender(); } } // namespace elv::editor diff --git a/Engine/src/Editor/Editor.h b/Engine/src/Editor/Editor.h index 6d9b249..3f74d84 100644 --- a/Engine/src/Editor/Editor.h +++ b/Engine/src/Editor/Editor.h @@ -1,5 +1,6 @@ #pragma once +#include "Panels/ProfileTelemetryPanel.h" #include "Panels/SceneHierarchyPanel.h" namespace elv::editor { @@ -12,6 +13,7 @@ class Editor { private: // panels SceneHierarchyPanel m_sceneHierarchyPanel; + ProfileTelemetryPanel m_profileTelemetry; // settings bool m_isVSync { false }; diff --git a/Engine/src/Editor/Panels/ProfileTelemetryPanel.cpp b/Engine/src/Editor/Panels/ProfileTelemetryPanel.cpp new file mode 100644 index 0000000..aafbeba --- /dev/null +++ b/Engine/src/Editor/Panels/ProfileTelemetryPanel.cpp @@ -0,0 +1,51 @@ +#include "ProfileTelemetryPanel.h" + +#include "Core/Application.h" +#include "Core/Profiler.h" +#include "Renderer/Renderer2D.h" + +#include +#include + +namespace elv::editor { +void ProfileTelemetryPanel::OnImGuiRender() +{ + ImGui::Begin("Telemetry"); + + const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_DefaultOpen + | ImGuiTreeNodeFlags_Framed + | ImGuiTreeNodeFlags_SpanAvailWidth + | ImGuiTreeNodeFlags_AllowItemOverlap + | ImGuiTreeNodeFlags_FramePadding; + + { + const bool opened = ImGui::TreeNodeEx("Performance", flags); + + if (opened) { + + ImGui::Text("FPS: %.1f", Application::GetTelemetry().fps); + ImGui::Text("Frame time %.3f ms", Application::GetTelemetry().frameTime); + + ImGui::Separator(); + + const auto& telemetry = ProfileTelemetry::GetInstance().GetTelemetry(); + + for (const auto& info : telemetry) { + ImGui::Text("%s: %.3f ms", info.first.c_str(), info.second); + } + + ImGui::TreePop(); + } + } + + { + const bool opened = ImGui::TreeNodeEx("2D Renderer", flags); + if (opened) { + ImGui::Text(" draw calls: %i", Renderer2D::GetTelemetry().drawCalls); + ImGui::TreePop(); + } + } + + ImGui::End(); +} +} // namespace elv::editor diff --git a/Engine/src/Editor/Panels/ProfileTelemetryPanel.h b/Engine/src/Editor/Panels/ProfileTelemetryPanel.h new file mode 100644 index 0000000..1d474bb --- /dev/null +++ b/Engine/src/Editor/Panels/ProfileTelemetryPanel.h @@ -0,0 +1,9 @@ +#pragma once + +namespace elv::editor { + +class ProfileTelemetryPanel { +public: + void OnImGuiRender(); +}; +} // namespace elv::editor diff --git a/Engine/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/Engine/src/Platform/OpenGL/OpenGLRendererAPI.cpp index d1acf4d..fd3fae0 100644 --- a/Engine/src/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Engine/src/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -43,6 +43,7 @@ GLenum GetTopology(const RenderTopology topology) void OpenGLRendererAPI::Init() { #ifdef DEBUG_MODE + // debug enabled glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(OpenGLMessageCallback, nullptr); @@ -50,10 +51,15 @@ void OpenGLRendererAPI::Init() glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, NULL, GL_FALSE); #endif + // blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // msaa glEnable(GL_MULTISAMPLE); + + // faceculling + glEnable(GL_CULL_FACE); } void OpenGLRendererAPI::SetViewport(std::uint32_t x, std::uint32_t y, std::uint32_t width, std::uint32_t height) diff --git a/Engine/src/Resources/AudioManager.cpp b/Engine/src/Resources/AudioManager.cpp index d6a1369..7318ead 100644 --- a/Engine/src/Resources/AudioManager.cpp +++ b/Engine/src/Resources/AudioManager.cpp @@ -33,7 +33,7 @@ void AudioManager::AddSound(const std::string& name, const std::string& path) { irrklang::ISoundSource* source = nullptr; { - PROFILE_SCOPE(fmt::format("Audio file {} is loaded in:", name)); + PROFILE_TO_LOG(fmt::format("Audio file {} is loaded in:", name)); source = m_engine->addSoundSourceFromFile(fmt::format("{}{}", fileSystem::SOUNDS_PATH, path).c_str(), irrklang::ESM_AUTO_DETECT, true); } if (source) { diff --git a/Engine/src/Resources/FontManager.cpp b/Engine/src/Resources/FontManager.cpp index 8ff04e9..b263687 100644 --- a/Engine/src/Resources/FontManager.cpp +++ b/Engine/src/Resources/FontManager.cpp @@ -17,7 +17,7 @@ constexpr uint16_t asciiCharNumToLoad = 128; void FontManager::Load(const std::string& fontName, const std::string& fontPath) { EL_CORE_INFO("Font {0} loading...", fontName); - PROFILE("Font is loaded in"); + PROFILE_TO_LOG("Font is loaded in"); auto it = m_fonts.find(fontName); if (it != m_fonts.end()) { diff --git a/Engine/src/Resources/ModelImporter.cpp b/Engine/src/Resources/ModelImporter.cpp index 93fd1b9..ce57b3b 100644 --- a/Engine/src/Resources/ModelImporter.cpp +++ b/Engine/src/Resources/ModelImporter.cpp @@ -94,7 +94,7 @@ void ProcessNode(aiNode* node, const aiScene* scene, lia::mat4 worldMatrix, Load void ImportModel(const std::string& path, LoadedMeshesInfo& info) { EL_CORE_INFO("Model {} loading...", path); - PROFILE(fmt::format("Model {} is loaded: ", path)); + PROFILE_TO_LOG(fmt::format("Model {} is loaded: ", path)); Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph); @@ -105,7 +105,7 @@ void ImportModel(const std::string& path, LoadedMeshesInfo& info) } { - PROFILE_SCOPE(fmt::format("Process model {} nodes: ", path)); + PROFILE_TO_LOG(fmt::format("Process model {} nodes: ", path)); ProcessNode(scene->mRootNode, scene, lia::mat4(), info); } } diff --git a/Engine/src/Resources/TextureManager.cpp b/Engine/src/Resources/TextureManager.cpp index 8cfaf79..9b69553 100644 --- a/Engine/src/Resources/TextureManager.cpp +++ b/Engine/src/Resources/TextureManager.cpp @@ -25,7 +25,7 @@ static void LoadTextureFromFile(std::vector& info.textureName = textureName; { - PROFILE_SCOPE(fmt::format("Texture {} is loaded in", textureName.c_str())) + PROFILE_TO_LOG(fmt::format("Texture {} is loaded in", textureName.c_str())) info.data = stbi_load(filepath.data(), &info.width, &info.height, &info.nrChannels, 0); } diff --git a/Engine/src/Scene/Components/LightComponent.h b/Engine/src/Scene/Components/LightComponent.h index 2aa561c..f8e9107 100644 --- a/Engine/src/Scene/Components/LightComponent.h +++ b/Engine/src/Scene/Components/LightComponent.h @@ -19,9 +19,9 @@ struct PointLightComponent { struct DirectionalLightComponent { bool enabled { false }; lia::vec3 direction { 0.0f, 1.0f, 0.0f }; - lia::vec3 ambient { 0.7f, 0.7f, 0.7f }; - lia::vec3 diffuse { 0.7f, 0.7f, 0.7f }; - lia::vec3 specular { 0.7f, 0.7f, 0.7f }; + lia::vec3 ambient { 0.4f, 0.4f, 0.4f }; + lia::vec3 diffuse { 0.4f, 0.4f, 0.4f }; + lia::vec3 specular { 0.4f, 0.4f, 0.4f }; }; struct SpotLightComponent { @@ -29,9 +29,9 @@ struct SpotLightComponent { bool flashlightMode { false }; // follow camera bool debugRender { false }; - lia::vec3 ambient { 0.7f, 0.7f, 0.7f }; - lia::vec3 diffuse { 0.7f, 0.7f, 0.7f }; - lia::vec3 specular { 0.7f, 0.7f, 0.7f }; + lia::vec3 ambient { 0.4f, 0.4f, 0.4f }; + lia::vec3 diffuse { 0.4f, 0.4f, 0.4f }; + lia::vec3 specular { 0.4f, 0.4f, 0.4f }; float cutOff { 12.5f }; float outerCutOff { 17.5f }; diff --git a/Engine/src/Scene/Scene.cpp b/Engine/src/Scene/Scene.cpp index f3d9928..62ec91c 100644 --- a/Engine/src/Scene/Scene.cpp +++ b/Engine/src/Scene/Scene.cpp @@ -74,7 +74,7 @@ void Scene::OnShutdown() void Scene::OnUpdate(float dt) { { - // PROFILE_SCOPE("Scene updated in: "); + PROFILE_SCOPE("Scene updated in: "); for (auto& system : m_systems) { system->OnUpdate(dt); } @@ -93,7 +93,7 @@ void Scene::OnUpdate(float dt) void Scene::OnRender(float dt) { - // PROFILE("Scene rendered in: "); + PROFILE("Scene rendered in: "); for (auto& system : m_systems) { system->OnRender(dt); } diff --git a/Engine/src/Scene/Systems/RenderSystem.cpp b/Engine/src/Scene/Systems/RenderSystem.cpp index 7ae8b2f..9575156 100644 --- a/Engine/src/Scene/Systems/RenderSystem.cpp +++ b/Engine/src/Scene/Systems/RenderSystem.cpp @@ -113,7 +113,7 @@ void RenderSystem::OnRender(float dt) // render static mesh { - // PROFILE_SCOPE("Static Meshes rendered in: "); + PROFILE_SCOPE("Static Meshes rendered in: "); auto meshPool = m_pScene->GetComponentPool(); auto& meshComponents = meshPool->GetComponents(); for (std::uint32_t i = 0; i < meshPool->Size(); ++i) { diff --git a/Sandbox3D/src/MeshModelSandbox.cpp b/Sandbox3D/src/MeshModelSandbox.cpp index 7c718b0..de393d8 100644 --- a/Sandbox3D/src/MeshModelSandbox.cpp +++ b/Sandbox3D/src/MeshModelSandbox.cpp @@ -1,10 +1,6 @@ #include "MeshModelSandbox.h" -#include -// #include -// #include #include -// #include #include #include @@ -89,19 +85,19 @@ MeshModelSandbox::MeshModelSandbox() dirLightComponent.direction = lia::vec3(0.0f, -1.0f, 0.0f); dirLightComponent.enabled = true; - /* auto flashLightEntity = scene.CreateEntity(); - scene.AddComponent(flashLightEntity, "Spot light"); - scene.AddComponent(flashLightEntity); - auto& spotLightComponent = scene.AddComponent(flashLightEntity); - spotLightComponent.enabled = false; - - for (size_t i = 0; i < kPointLightsAmount; ++i) { - auto pointLightEntity = scene.CreateEntity(); - scene.AddComponent(pointLightEntity, fmt::format("Point light {}", i)); - scene.AddComponent(pointLightEntity, kPointLightPositions[i]); - auto& pointLightComponent = scene.AddComponent(pointLightEntity); - pointLightComponent.enabled = false; - }*/ + auto flashLightEntity = scene.CreateEntity(); + scene.AddComponent(flashLightEntity, "Spot light"); + scene.AddComponent(flashLightEntity); + auto& spotLightComponent = scene.AddComponent(flashLightEntity); + spotLightComponent.enabled = true; + + for (size_t i = 0; i < kPointLightsAmount; ++i) { + auto pointLightEntity = scene.CreateEntity(); + scene.AddComponent(pointLightEntity, fmt::format("Point light {}", i)); + scene.AddComponent(pointLightEntity, kPointLightPositions[i]); + auto& pointLightComponent = scene.AddComponent(pointLightEntity); + pointLightComponent.enabled = true; + } // default environment SetEnvironment(0);