标签:profile pos ati lin animate 上下文 article top stat
调试及开发工具
日志及跟踪
printf调试法有时是很好的调试方法。因为有些bug很难用断点和监视窗口跟踪;有些bug有时间依赖性,只有全速运行时才会出现等等。这事打印信息就是很好的调试方法。
win32窗口应用程序没有控制台显示输出的函数,但是visual studio中有函数OutputDebugString()打印信息。但是它不支持格式化输出,所以Windows游戏引擎以自定义函数包装此函数
#include<stdio.h> #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include<windows.h> int VDebugPrintF(const char* format, va_list argList){ const U32 MAX_CHARS = 1023; static char s_buffer[MAX_CHARS + 1]; int charsWritten = vsnprintf(s_buffer, MAX_CHARS, format, argList); s_buffer[MAX_CHARS] = ‘\0‘;//字符串以‘\0‘结尾 OutputDebugStringA(s_buffer); //OutputDebugString(s_buffer);//VS2012不兼容 return charsWritten; } int DebugPrintF(const char *format, ...){ va_list argList;//处理变参(...)的一组宏,具体参考:http://blog.csdn.net/aihao1984/article/details/5953668 _crt_va_start(argList, format);//VS2008定义方式:#define va_start _crt_va_start int charsWritten = VDebugPrintF(format, argList); _crt_va_end(argList); return charsWritten; }
冗长级别
当你在代码中添加了适当的打印语句后,最好能保留它们,以便以后需要时使用。为此,引擎通常提供一些机制来控制冗长级别。根据全局的冗长级别,打印出对应的信息。简单的实现方式:把当前系统的冗长级别存储在一个全局整数变量中,或可命名为g_verbosity。然后提供一个函数VerboseDebugPrintF()函数,其首个参数是冗长级别。
int g_verbosity = 0; void VerboseDebugPrintF(int verbosity, const char *format, ...){ if (g_verbosity >= verbosity){ va_list argList; _crt_va_start(format, argList); VDebugPrintF(format, argList); _crt_va_end(argList); } }
频道
将调试输出分类位频道是很有用的功能。例如PlayStation3,可以把调试输出到14个TTY窗口之一,而且每条消息还会抄送至一个特别的TTY窗口(它包含所有的输出)。
就算是一些只有单个输出窗口的系统中,也可以通过把每个频道显示不同颜色来划分输出信息。而且还可以实现过滤器(filter),开关相应的过滤器,能够只显示对应频道的调试输出。
实现方法是在调试打印函数中加入频道参数来实现该功能,频道可以用数字标识,使用enum表示更好,也可以使用字符串或字符串散列标识符命名频道。如果少于32或64个频道,直接用32位或64位掩码过滤频道。
把输出同时抄写到日志文件中
把所有调试信息同时抄写到一个或多个日志文件中,可以方便事后诊断问题。应当不管当前的冗长级别和频道,而把所有调试信息都写入日志文件。
每次调用调试输出函数后都对日志文件清空缓冲,以确保万一游戏崩溃时日志文件仍会包含最后的输出。通常最后的输出对确定崩溃的原因很关键,但是清空缓冲成本很高。因此,以下情况下才应该清空缓冲:
崩溃报告
有些游戏引擎会在崩溃时放出特别的文本或日志。大多数系统都有一个顶层的异常处理函数,它可以捕获大部分的崩溃情形。你可以在此函数中打印各种有用信息。
崩溃报告可包含的信息:
调试用的绘图功能
大部分游戏引擎会提供一组API,去绘画有颜色的线条、简单图形及三维文本。这些API称为调试绘图。因为这些绘画仅为了在开发及调试期间做可视化,在游戏的发布版中会移除。相对于看代码中的数学公式,直接通过图形看绘图结果能更快的知道逻辑和数学错误。
调试绘图API
满足的要求:
游戏内置菜单
在游戏运行期间,开发人员能直接配置各个子系统的配置选项,这样会很方便。因为,它不需要重新编辑代码,编译连接。游戏中配置菜单选项,最简单有效的方法是提供游戏内置菜单:
游戏内置主控台
有些引擎提供游戏内置主控台,他提供命令式的接口让用户使用引擎功能;相对游戏内置菜单,游戏内置主控台虽然不太方便,但是他提供更丰富的接口,使用户几乎能使用所有引擎功能。
调用摄像机和游戏暂停
游戏内置主控台或游戏内置菜单最好附有两个功能:
暂停游戏时,仍需控制摄像机;可以通过停止逻辑时钟,保持渲染引擎和摄像机控制系统来实现。
慢动作模式也很有用,可以通过游戏时钟和真实时钟的更新速率不同来实现。
作弊
作弊是调试游戏的重要方法。如果为了调试游戏还要死命玩到某关,在调试,效率上太差了。因此,需要作弊。像是不死身、给玩家武器、无尽弹药、选择角色网络等。
屏幕截图及录像
获取屏幕截图是有用的工具。通常这些截图会放到某个预设的文件夹中,并以日期来命名保证文件的唯一性。
有些引擎也提供全面的录像功能。系统是以目标帧率来获取屏幕截图,然后存成视频格式文件。
获取屏幕截图很慢,因为从显存传送帧缓冲至内存的时间开销(图形硬件通常不会优化此操作)和图像存盘。
游戏内置性能剖析
前面提到过需到第三方的剖析工具,但是不一定能在该游戏机上运行,因此,游戏通常会内置性能剖析工具。
层阶式剖析:层阶式的函数调用;C/C++中根函数一般是main()或WinMain(),但从技术上说真正的根是C标准运行时库中的启动函数。
两个方面度量函数的耗时:函数的执行时间和函数的调用次数;
游戏内性能剖析工具通常手动在程序中添加测控,来得到函数的执行时间:
//一个典型的游戏循环如下: while (!quitGame){ PollJoypad(); UpdateGameObjects(); UpdateAllAnimateions(); PostProcessJoints(); DetectCollisions(); RunPhysics(); GenerateFinalAnimationPoses(); UpdateCameras(); RenderScene(); UpdateAudio(); }
如果要剖析上面代码的性能,可能这样插入测控:
while (!quitGame){ { PROFILE("Poll Joypad"); PollJoypad(); } { PROFILE("Game Objects Update"); UpdateGameObjects(); } { PROFILE("Animateions"); UpdateAllAnimateions(); } { PROFILE("Joint Post-Processing"); PostProcessJoints(); } { PROFILE("Collisions"); DetectCollisions(); } { PROFILE("Physics"); RunPhysics(); } { PROFILE("Animation Finaling"); GenerateFinalAnimationPoses(); } { PROFILE("Cameras"); UpdateCameras(); } { PROFILE("Rendering"); RenderScene(); } { PROFILE("Audio"); UpdateAudio(); } }
上面代码的PROFILE()宏会以一个类实现,该类的构造函数负责计时,析构函数停止计时,并以指定的名字记录执行时间。它只会为块作用域内代码计时
struct AutoProfile { AutoProfile(const char* name){ m_name = name; m_startTime = QueryPerformanceCounter(); } ~AutoProfile(){ __int64 endtime = QueryPerformanceCounter(); __int64 elapsedTime = endtime - m_startTime; g_profileManager.storeSample(m_name, elapsedTime); } const char *m_name; __int64 m_startTime; }; #define PROFILE(name) AutoProfile p(name)
通过加入一些代码去描述剖析采样的层阶关系。
//此代码声明多个剖析样本箱,指明样本箱的名字,以及父样本箱的名字(若有) ProfilerDeclareSampleBin("Rendering", NULL); ProfilerDeclareSampleBin("Visibility", "Rendering"); ProfilerDeclareSampleBin("ShaderSetUp", "Rendering"); ProfilerDeclareSampleBin("Materials", "ShaderSetUp"); ProfilerDeclareSampleBin("SubmitGeo", "Rendering"); ProfilerDeclareSampleBin("Audio", NULL); //......
游戏内置的内存统计和泄漏检测
很多游戏引擎会实现自定义的内存追踪工具。该工具的难点:
好的内存追踪工具:
标签:profile pos ati lin animate 上下文 article top stat
原文地址:http://www.cnblogs.com/yeqluofwupheng/p/7711575.html