ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

<2021SC@SDUSC> 开源游戏引擎 Overload 代码模块分析 之 OvGame(五)—— Debug(下)FrameInfo & GameProfiler

2021-12-08 22:33:35  阅读:182  来源: 互联网

标签:OvUI 2021SC FrameInfo Overload GameProfiler window Debug 函数


2021SC@SDUSC
开源游戏引擎 Overload 代码模块分析 之 OvGame(五)—— Debug(下)FrameInfo & GameProfiler

目录

前言

本篇是 OvGame 的 Debug 的下篇,将探究其最后两个部分 FrameInfo & GameProfiler。想了解 Debug 的另一个部分请前往 Debug(上) 阅读。

另外,若想先大致了解该引擎各个大模块,可前往笔者这篇相关文章查看。
若想了解 OvGame 大纲,可前往笔者这篇文章

分析

1、FrameInfo

1.1 FrameInfo.h

1.1.1 头文件

#include <OvRendering/Core/Renderer.h>
#include <OvWindowing/Window.h>

#include <OvUI/Panels/PanelUndecorated.h>
#include <OvUI/Widgets/Texts/TextColored.h>

该文件的头文件都来自 Overload 的其它模块,暂不详述

1.1.2 主要代码

该文件主要代码是 FrameInfo 类,可以生成 Frame Information,的展示面板。定义如下:

	class FrameInfo : public OvUI::Panels::PanelUndecorated
	{
	public:
		/**
		* Constructor
		* @param p_renderer
		* @param p_window
		*/
		FrameInfo(OvRendering::Core::Renderer& p_renderer, OvWindowing::Window& p_window);

		/**
		* Update the data
		* @parma p_deltaTime
		*/
		void Update(float p_deltaTime);

	private:
		OvRendering::Core::Renderer&	m_renderer;
		OvWindowing::Window&			m_window;

		OvUI::Widgets::Texts::TextColored* m_frameInfo[3];
	};

显然,该类同上篇文章探究的类一样,继承了 OvUI 的 PanelUndecorated 类,详情请读者前往 Utils(终)大纲及 FPSCounter & Debug(上)大纲及 DriverInfo 查看。另外,该类定义的函数已有注释,不多说;定义的变量分别是渲染器类、窗口类、有色文字类类数组。

1.2 FrameInfo.cpp

该文件仅包含上文的 FrameInfo.h 头文件,所以直接看函数:

FrameInfo() 函数

OvGame::Debug::FrameInfo::FrameInfo(OvRendering::Core::Renderer& p_renderer, OvWindowing::Window& p_window) :
	m_renderer(p_renderer),
	m_window(p_window)
{
	m_defaultHorizontalAlignment = OvUI::Settings::EHorizontalAlignment::LEFT;
	m_defaultVerticalAlignment = OvUI::Settings::EVerticalAlignment::BOTTOM;
	m_defaultPosition.x = static_cast<float>(p_window.GetSize().first) - 10.f;
	m_defaultPosition.y = static_cast<float>(p_window.GetSize().second) - 10.f;

	m_frameInfo[0] = &CreateWidget<OvUI::Widgets::Texts::TextColored>("", OvUI::Types::Color::Yellow);
	m_frameInfo[1] = &CreateWidget<OvUI::Widgets::Texts::TextColored>("", OvUI::Types::Color::Yellow);
	m_frameInfo[2] = &CreateWidget<OvUI::Widgets::Texts::TextColored>("", OvUI::Types::Color::Yellow);
}

这是类的构造函数,首先,使用参数初始化表为渲染器和窗口赋值;其次,与上篇文章也一样,使用格式对齐枚举类,为父类 APanelTransformable 类的变量 m_defaultHorizontalAlignment 与 m_defaultVerticalAlignment 赋值,实现左对齐与底对齐;接着,同样是其父类 APanelTransformable 的变量 m_defaultPosition,用 m_window 的 GetSize() 获得窗口宽度、高度,设置面板的默认位置。

最后,为类数组 m_frameInfo 的三个对象都进行赋值,使用的是 CreateWidget() 函数,该函数在 Utils(终)大纲及 FPSCounter & Debug(上)大纲及 DriverInfo 也已经解析过,请自行前往查看。

Update() 函数

void OvGame::Debug::FrameInfo::Update(float p_deltaTime)
{
	auto& frameInfo = m_renderer.GetFrameInfo();

	m_frameInfo[0]->content = "Triangles: " + std::to_string(frameInfo.polyCount);
	m_frameInfo[1]->content = "Batches: " + std::to_string(frameInfo.batchCount);
	m_frameInfo[2]->content = "Instances: " + std::to_string(frameInfo.instanceCount);

	SetPosition({ 10.0f , static_cast<float>(m_window.GetSize().second) - 10.f });
	SetAlignment(OvUI::Settings::EHorizontalAlignment::LEFT, OvUI::Settings::EVerticalAlignment::BOTTOM);
}

首先,GetFrameInfo() 返回 OvRendering::Core 的 Renderer 类的结构体 FrameInfo,赋值 auto&(自判定类型)的 frameInfo;接着,m_frameInfo 的字符串变量 content(内容)依次分别赋值三角形个数、批次数、实例数,其中数据是直接读取结构体 FrameInfo 中的数据;然后,调用 APanelTransformable 父类的 SetPosition() 函数,设置面板的初始位置;最后,将左对齐方式和底对齐方式传入 APanelTransformable 类的函数 SetAlignment() 设置对齐格式。

2、GameProfiler

2.1 GameProfiler.h

2.1.1 头文件

#include <OvRendering/Core/Renderer.h>
#include <OvWindowing/Window.h>

#include <OvAnalytics/Profiling/Profiler.h>
#include <OvUI/Panels/PanelUndecorated.h>
#include <OvUI/Widgets/Texts/TextColored.h>
#include <OvUI/Widgets/Layout/Group.h>
#include <OvUI/Widgets/Buttons/Button.h>

该文件的头文件都来自 Overload 的其它模块,暂不详述

2.1.2 主要代码

主要代码是 GameProfiler 类,可以生成 profiling information,配置文件信息,的面板。定义比较长,先看其中函数的定义,如下:

class GameProfiler : public OvUI::Panels::PanelUndecorated
	{
	public:
		/**
		* Constructor
		* @param p_window
		* @param p_frequency
		*/
		GameProfiler(OvWindowing::Window& p_window, float p_frequency);

		/**
		* Update the data
		* @param p_deltaTime
		*/
		void Update(float p_deltaTime);

	private:
		OvUI::Types::Color CalculateActionColor(double p_percentage) const;
		std::string GenerateActionString(OvAnalytics::Profiling::ProfilerReport::Action& p_action);

该类包括了两个公有函数和两个私有函数,公有函数有注释,不多说;私有函数具体定义在 GameProfiler.cpp 中,暂不叙述。

	private:

		float m_frequency;
		float m_timer = 0.f;

		OvAnalytics::Profiling::Profiler m_profiler;

		OvWindowing::Window& m_window;
		OvUI::Widgets::AWidget* m_separator;
		OvUI::Widgets::Texts::TextColored* m_elapsedFramesText;
		OvUI::Widgets::Texts::TextColored* m_elapsedTimeText;
		OvUI::Widgets::Layout::Group* m_actionList;
	};

该类声明了多个私有变量,大多数之前的文章都有了解过。其中,m_frequency 用于记录时间周期;m_timer 用于记录累计经过的时间;Profiler 是一个配置文件类,收集了正在运行程序的相关数据;Window 是窗口类;AWidget 是部件类;TextColored 是有色文本类;Group 是可以包含其他小部件的小部件类。

2.2 GameProfiler.cpp

2.2.1 头文件

该文件中又引入了更多的 Overload 其它模块的头文件,也暂不详述

#include "OvGame/Debug/GameProfiler.h"

#include <OvDebug/Utils/Logger.h>
#include <OvUI/Widgets/Visual/Separator.h>
#include <OvAnalytics/Profiling/ProfilerSpy.h>

2.2.2 主要代码

在函数之前,还加入了下列的命名空间从而使代码简洁:

using namespace OvUI::Panels;
using namespace OvUI::Widgets;
using namespace OvUI::Types;

现在,先了解两个私有函数,都很简单,不作过多叙述:

CalculateActionColor() 函数
OvUI::Types::Color OvGame::Debug::GameProfiler::CalculateActionColor(double p_percentage) const
{
	if (p_percentage <= 25.0f)		return { 0.0f, 1.0f, 0.0f, 1.0f };
	else if (p_percentage <= 50.0f) return { 1.0f, 1.0f, 0.0f, 1.0f };
	else if (p_percentage <= 75.0f) return { 1.0f, 0.6f, 0.0f, 1.0f };
	else							return { 1.0f, 0.0f, 0.0f, 1.0f };
}

该函数负责计算操作的颜色,类型是颜色结构体 Color。显然,传入的参数,含义是操作完成度百分比,它将影响返回的颜色数据.。

GenerateActionString() 函数
std::string OvGame::Debug::GameProfiler::GenerateActionString(OvAnalytics::Profiling::ProfilerReport::Action & p_action)
{
	std::string result;

	result += "[" + p_action.name + "]";
	result += std::to_string(p_action.duration) + "s (total) | ";
	result += std::to_string(p_action.duration / p_action.calls) + "s (per call) | ";
	result += std::to_string(p_action.percentage) + "%% | ";
	result += std::to_string(p_action.calls) + " calls";

	return result;
}

该函数的类型是 string,传入的是结构体 ProfilerReport,含义为被调用方法的操作;返回的是结构体内的名字、持续时间等信息组合成的字符串信息。

简单一提,在 OvEditor::Panels::Profiler 类中,也有与上述两个函数同名同代码的函数,不可混淆。

接着,继续了解公有函数:

GameProfiler() 函数
OvGame::Debug::GameProfiler::GameProfiler(OvWindowing::Window& p_window, float p_frequency) : m_frequency(p_frequency), m_window(p_window)
{
	m_defaultHorizontalAlignment = OvUI::Settings::EHorizontalAlignment::LEFT;
	m_defaultPosition = { 10.0f, 10.0f };

	CreateWidget<Texts::Text>("Profiler state: ").lineBreak = true;

	m_elapsedFramesText = &CreateWidget<Texts::TextColored>("", Color(1.f, 0.8f, 0.01f, 1));
	m_elapsedTimeText = &CreateWidget<Texts::TextColored>("", Color(1.f, 0.8f, 0.01f, 1));
	m_separator = &CreateWidget<OvUI::Widgets::Visual::Separator>();
	m_actionList = &CreateWidget<Layout::Group>();

	m_actionList->CreateWidget<Texts::Text>("Action | Total duration | Frame Duration | Frame load | Total calls");

	m_profiler.Enable();

	m_elapsedFramesText->enabled = true;
	m_elapsedTimeText->enabled = true;
	m_separator->enabled = true;
}

该函数是构造函数,首先,参数初始化表初始化频率、窗口;接着,同上文一样,设置左对齐和面板默认位置,CreateWidget() 函数创建文本面板来显示文件数据,并设置 lineBreak = true,即允许换行;然后,依次用 CreateWidget() 设置四个私有变量;而后,m_actionList 在赋值后又调用了 CreateWidget() 设置其中的文字,含义与上文提及 ProfilerReport 结构体对应;最后,依次设置上列设置好的部件激活,这样才能被绘制。

Update() 函数

该函数比较长,我们一段一段探究:

void OvGame::Debug::GameProfiler::Update(float p_deltaTime)
{
	PROFILER_SPY("Game Profiler Update");

	m_position = { 10.0f, static_cast<float>(m_window.GetSize().second / 2) };

	m_timer += p_deltaTime;

首先,使用 PROFILER_SPY,笔者之前的文章已经提及过,此处是配置文件更新;然后设置面板位置与时间。

接下来,判断 m_profiler 是否激活(正如构造函数中提及的):

	if (m_profiler.IsEnabled())
	{
		m_profiler.Update(p_deltaTime);

通过后,先调用 OvEditor::Core::Editor::Update() 进行一系列的更新,包括全局快捷键、当前编辑器模式等等;然后,判断如果记录的时间超过设定的周期时间,那么进入 while 循环:

		while (m_timer >= m_frequency)
		{			
			OvAnalytics::Profiling::ProfilerReport report = m_profiler.GenerateReport();
			m_profiler.ClearHistory();
			m_actionList->RemoveAllWidgets();

			m_elapsedFramesText->content = "Elapsed frames: " + std::to_string(report.elapsedFrames);
			m_elapsedTimeText->content = "Elapsed time: " + std::to_string(report.elaspedTime);

			m_actionList->CreateWidget<Texts::Text>("Action | Total duration | Frame Duration | Frame load | Total calls");

首先,m_profiler 调用 GenerateReport() 返回包含硬件信息的 HardwareReport 结构体,而后 m_profiler 调用 ClearHistory() 清空所有收集数据的记录,操作列表 m_actionList 调用 RemoveAllWidgets() 移除所有部件;接着,和构造函数一样设置两个文本和操作列表的文本;然后还没有退出 while 循环,继续进入下面的 for 循环:

			for (auto& action : report.actions)
			{
				auto color = CalculateActionColor(action.percentage);
				m_actionList->CreateWidget<Texts::TextColored>(GenerateActionString(action), color);
			}
		
			m_timer -= m_frequency;
		}
	}
}

该循环的长度取决于 report 的 vector 容器 actions,循环内依次对 actions 的成员操作:先调用上文的 CalculateActionColor() 得到该操作的进度对应的颜色,再用 CreateWidget() 创造有色文本,内容即上文的 GenerateActionString() 转换后的该操作信息的字符串。

操作完所有的 action 后退出 for 循环,将 m_timer 扣除这一个周期的时间;如果扣除后 m_timer 小于单位周期时间了,才退出 while 循环,结束函数。

总结

本篇解析了 OvGame 的 Debug 的最后两部分,Debug 文件的所有内容就解析完毕了。总体看来,Debug 就是一些信息的展示操作,并不复杂。

现在,我们已经了解完了 OvGame 的 Utils 和 Debug 两块文件,就可以继续停更的 Core 文件的后续内容了。因此下一篇,我们将可以继续了解 OvGame 之 Core 文件的 Game 部分

clapping

标签:OvUI,2021SC,FrameInfo,Overload,GameProfiler,window,Debug,函数
来源: https://blog.csdn.net/Egovix/article/details/121693236

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有