Skip to content

Commit

Permalink
Added performance telemetry
Browse files Browse the repository at this point in the history
- editor telemetry panel
- performance telemetry collection logic
- enabled faceculling
  • Loading branch information
denyskryvytskyi committed Apr 2, 2024
1 parent 971bd85 commit 289d04f
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 79 deletions.
3 changes: 3 additions & 0 deletions Engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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"
Expand Down Expand Up @@ -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()

Expand Down
84 changes: 53 additions & 31 deletions Engine/src/Core/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "FileSystem.h"
#include "Input.h"
#include "Profiler.h"
#include "SettingsConfig.h"
#include "Timer.h"
#include "Window.h"
Expand Down Expand Up @@ -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<TextComponent>(m_fpsCounterEntityId).text
= fmt::format("{:0.3f} ms ({} fps)", s_telemetry.frameTime, static_cast<int>(std::floor(s_telemetry.fps)));
if (gEngineSettings.enableFpsCounter) {
GetScene().GetComponent<TextComponent>(m_fpsCounterEntityId).text
= fmt::format("{:0.3f} ms ({} fps)", s_telemetry.frameTime, static_cast<int>(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();
}
}
}

Expand Down
10 changes: 10 additions & 0 deletions Engine/src/Core/Profiler.cpp
Original file line number Diff line number Diff line change
@@ -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
32 changes: 30 additions & 2 deletions Engine/src/Core/Profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,44 @@
#include <string>

namespace elv {
class ProfileTelemetry {
public:
static ProfileTelemetry& GetInstance()
{
static ProfileTelemetry instance;
return instance;
}

const std::unordered_map<std::string, float>& GetTelemetry() const { return m_telemetry; }

void Update(const std::string& name, const float value);

private:
std::unordered_map<std::string, float> 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;
};
Expand All @@ -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(...)
Expand Down
4 changes: 2 additions & 2 deletions Engine/src/Core/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ class Timer {
float Elapsed() const { return std::chrono::duration_cast<seconds>(clock::now() - m_start).count(); }
float ElapsedMs() const { return std::chrono::duration_cast<milliseconds>(clock::now() - m_start).count(); }

// static long long GetTimeNow() { return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); }

private:
using clock = std::chrono::high_resolution_clock; // QueryPerformanceCounter
using seconds = std::chrono::duration<float, std::ratio<1>>;
Expand All @@ -28,4 +26,6 @@ class Timer {
std::chrono::time_point<clock> m_start;
};

inline long long GetTimeNow() { return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); }

} // namespace elv
15 changes: 2 additions & 13 deletions Engine/src/Editor/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "Core/Window.h"
#include "Renderer/RenderCommand.h"
#include "Renderer/Renderer.h"
#include "Renderer/Renderer2D.h"

#include <imgui.h>

Expand Down Expand Up @@ -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 ============
Expand All @@ -73,5 +60,7 @@ void Editor::OnImGuiRender()
if (gEngineSettings.enableSceneGraph) {
m_sceneHierarchyPanel.OnImGuiRender();
}

m_profileTelemetry.OnImGuiRender();
}
} // namespace elv::editor
2 changes: 2 additions & 0 deletions Engine/src/Editor/Editor.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "Panels/ProfileTelemetryPanel.h"
#include "Panels/SceneHierarchyPanel.h"

namespace elv::editor {
Expand All @@ -12,6 +13,7 @@ class Editor {
private:
// panels
SceneHierarchyPanel m_sceneHierarchyPanel;
ProfileTelemetryPanel m_profileTelemetry;

// settings
bool m_isVSync { false };
Expand Down
51 changes: 51 additions & 0 deletions Engine/src/Editor/Panels/ProfileTelemetryPanel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "ProfileTelemetryPanel.h"

#include "Core/Application.h"
#include "Core/Profiler.h"
#include "Renderer/Renderer2D.h"

#include <imgui.h>
#include <imgui_internal.h>

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
9 changes: 9 additions & 0 deletions Engine/src/Editor/Panels/ProfileTelemetryPanel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

namespace elv::editor {

class ProfileTelemetryPanel {
public:
void OnImGuiRender();
};
} // namespace elv::editor
6 changes: 6 additions & 0 deletions Engine/src/Platform/OpenGL/OpenGLRendererAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ 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);

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)
Expand Down
2 changes: 1 addition & 1 deletion Engine/src/Resources/AudioManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion Engine/src/Resources/FontManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Loading

0 comments on commit 289d04f

Please sign in to comment.