diff options
Diffstat (limited to '')
-rw-r--r-- | game/code/debug/alldebug.cpp | 3 | ||||
-rw-r--r-- | game/code/debug/debuginfo.cpp | 782 | ||||
-rw-r--r-- | game/code/debug/debuginfo.h | 204 | ||||
-rw-r--r-- | game/code/debug/profiler.cpp | 753 | ||||
-rw-r--r-- | game/code/debug/profiler.h | 206 | ||||
-rw-r--r-- | game/code/debug/ps2perf.hpp | 263 | ||||
-rw-r--r-- | game/code/debug/section.cpp | 236 | ||||
-rw-r--r-- | game/code/debug/section.h | 108 |
8 files changed, 2555 insertions, 0 deletions
diff --git a/game/code/debug/alldebug.cpp b/game/code/debug/alldebug.cpp new file mode 100644 index 0000000..d11b9ea --- /dev/null +++ b/game/code/debug/alldebug.cpp @@ -0,0 +1,3 @@ +#include <debug/debuginfo.cpp> +#include <debug/profiler.cpp> +#include <debug/section.cpp> diff --git a/game/code/debug/debuginfo.cpp b/game/code/debug/debuginfo.cpp new file mode 100644 index 0000000..7b41485 --- /dev/null +++ b/game/code/debug/debuginfo.cpp @@ -0,0 +1,782 @@ +//============================================================================== +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: debuginfo.cpp +// +// Description: In-game visual debug output +// +// History: 2002/07/02 + Migrated from Mirth -- Darwin Chau +// +//============================================================================== + +//======================================== +// System Includes +//======================================== +#include <string.h> +// FTech +#include <raddebug.hpp> +#include <raddebugwatch.hpp> +// Pure3D +#include <p3d/font.hpp> +#include <p3d/matrixstack.hpp> +#include <p3d/texturefont.hpp> +#include <p3d/unicode.hpp> +#include <p3d/utility.hpp> +#include <pddi/pddi.hpp> + +//======================================== +// Project Includes +//======================================== +#include <debug/debuginfo.h> +#include <debug/section.h> + +#include <memory/srrmemory.h> + +#ifdef DEBUGINFO_ENABLED + +//****************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//****************************************************************************** + +//The Adlib font. <sigh> +static unsigned char gFont[] = +#include <font/defaultfont.h> + +// Static pointer to instance of singleton. +DebugInfo* DebugInfo::_Instance = NULL; + +static void Next() +{ + DebugInfo::GetInstance()->OnNext(); +} + +static void Switch() +{ + DebugInfo::GetInstance()->OnSwitch(); +} + +//****************************************************************************** +// +// Public Member Functions +// +//****************************************************************************** + + +//============================================================================== +// DebugInfo::DebugInfo +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +DebugInfo::DebugInfo() : + _pDebugFont(NULL), + _pTypeFace(NULL), + _NumSection(0), + _StackSize(0), + _CurrentSection(0), + _DebugMenuTime(0.0f), + _isRenderEnabled(false), + _isCreationSectionOpen(false), + _mode(OFF), + _shader(NULL) +{ + for(int i=0; i<MaxSections; i++) + { + _ppSections[i] = NULL; + } + + radDbgWatchAddFunction( "Next Section", (RADDEBUGWATCH_CALLBACK)Next, 0, "DebugInfo" ); + radDbgWatchAddFunction( "Toggle Display", (RADDEBUGWATCH_CALLBACK)Switch, 0, "DebugInfo" ); +} + + +//============================================================================== +// DebugInfo::~DebugInfo +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +DebugInfo::~DebugInfo() +{ + if(_pDebugFont) + { + _pDebugFont->Release (); + } + + if(_shader) + _shader->Release(); + + int i; + for(i=0; i<MaxSections; i++) + { + if(_ppSections[i]) + delete (GMA_DEBUG, _ppSections[i]); + } +} + + +//============================================================================== +// DebugInfo::CreateInstance +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::CreateInstance() +{ +MEMTRACK_PUSH_GROUP( "DebugInfo" ); + HeapMgr()->PushHeap( GMA_DEBUG ); + + _Instance = new DebugInfo; + + HeapMgr()->PopHeap ( GMA_DEBUG ); +MEMTRACK_POP_GROUP( "DebugInfo" ); +} + + +//============================================================================== +// DebugInfo::CreateNewSection +//============================================================================== +// +// Description: Creates a new section +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::CreateNewSection( const char* section ) +{ + HeapMgr()->PushHeap( GMA_DEBUG ); + //Lazy section allocation + if(_ppSections[_NumSection]) + { + _ppSections[_NumSection]->Reset( section ); + } + else + { + if( _pDebugFont == NULL ) + { + // + // find the font + // + _pDebugFont = p3d::find<tTextureFont>("adlibn_20"); + + if( _pDebugFont == NULL ) + { + // Convert memory buffer into a texturefont. + // + p3d::load(gFont, DEFAULTFONT_SIZE, GMA_DEBUG); + _pDebugFont = p3d::find<tTextureFont>("adlibn_20"); + rAssertMsg(_pDebugFont, ("ERROR - debug font not found.")); + } + + _pDebugFont->AddRef(); + } + + _ppSections[_NumSection] = new Section( _pDebugFont, section ); + } + //_pStack[_StackSize++] = _NumSection; + _NumSection++; + HeapMgr()->PopHeap( GMA_DEBUG ); +} + +//============================================================================== +// DebugInfo::DestroyInstance +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::DestroyInstance() +{ + delete(GMA_DEBUG, _Instance); +} + + +//============================================================================== +// DebugInfo::GetInstance +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +DebugInfo* DebugInfo::GetInstance() +{ + if(!_Instance) + { + CreateInstance(); + } + + return _Instance; +} + +//============================================================================== +// DebugInfo::InitializeStaticVariables +//============================================================================== +// +// Description: Initializes all the sections that we're ever going to use +// +// Parameters: none +// +// Return: none +// +//============================================================================== +void DebugInfo::InitializeStaticVariables() +{ + GetInstance()->CreateNewSection( "Vehicle Terrain Type" ); + GetInstance()->CreateNewSection( "Vehicle Shit" ); +} + +//============================================================================== +// DebugInfo::OnSwitch +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::OnSwitch() +{ + _mode = (Mode) ((_mode + 1) % MODE_MAX); + + if(_mode == OFF) + { + _isRenderEnabled = false; + _isBackgroundEnabled = false; + } + else if(_mode == BACKGROUND) + { + _isRenderEnabled = true; + _isBackgroundEnabled = true; + } + else if(_mode == NOBACKGROUND) + { + _isRenderEnabled = true; + _isBackgroundEnabled = false; + } + +} + + +//============================================================================== +// DebugInfo::Push +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +bool DebugInfo::Push(char* szSection) +{ +MEMTRACK_PUSH_GROUP( "DebugInfo" ); + HeapMgr()->PushHeap (GMA_DEBUG); + + rAssert(szSection); + rAssert(_StackSize<MaxStackSize); + + int i; + bool bFound = false; + + //Check for exsisting section + for(i=0;i<_NumSection;i++) + { + //look for the global section (NULL) or a matching name + const char* szName = _ppSections[i]->GetName(); + if(0==strcmp(szSection,szName)) + { + _pStack[_StackSize++] = i; + bFound = true; + break; + } + } + //Create a new section + if(!bFound) + { + CreateNewSection( szSection ); + } +MEMTRACK_POP_GROUP( "DebugInfo" ); + HeapMgr()->PopHeap (GMA_DEBUG); + + //Return true if this is the current section + return (bFound && i==_CurrentSection); +} + + +//============================================================================== +// DebugInfo::GetCurrentSection +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +const char* DebugInfo::GetCurrentSection() +{ + Section *pSect = _ppSections[_CurrentSection]; + if (pSect && _isRenderEnabled) + return (pSect->GetName()); + else + return (NULL); +} + + +//============================================================================== +// DebugInfo::Pop +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::Pop() +{ + rAssert( _NumSection > 0 ); + rAssert( _StackSize >= 0 ); + --_StackSize; +} + + + +//============================================================================== +// int SignedMod +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// + +//============================================================================== +int SignedMod(int a, int b) +{ + rAssert(b>0); + if (a>=0) return (a%b); + else return (b - ((-a)%b)); +} + + +//============================================================================== +// DebugInfo::Toggle +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::Toggle(int step) +{ + _CurrentSection = SignedMod(_CurrentSection+step, _NumSection); + _DebugMenuTime = 1.0f; +} + + +//============================================================================== +// DebugInfo::SetAutoReset +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::SetAutoReset(bool autoreset) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->SetAutoReset(autoreset); +} + + + +//============================================================================== +// DebugInfo::Reset +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::Reset(char* sectionName) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->Reset(sectionName); +} + + +//============================================================================== +// DebugInfo::AddLine +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddLine(const rmt::Vector& a, const rmt::Vector& b, tColour colour) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->AddLine(a, b, colour); +} + + +//============================================================================== +// DebugInfo::AddHVector +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddHVector(rmt::Vector o, rmt::Vector v, float h, tColour colour) +{ + // Add the origin to the vector + v.Add(o); + // Add the elevation + v.Add(rmt::Vector(0, h, 0)); + o.Add(rmt::Vector(0, h, 0)); + // Then, its a regular line + AddLine(o, v, colour); +} + + +//============================================================================== +// DebugInfo::AddStar +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddStar(const rmt::Vector& vx, tColour colour, float scale) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + //Draw a kind of star + rmt::Vector a, b; + a = b = vx; + a.x += scale; b.x -= scale; + AddLine( a, b, colour ); + a = b = vx; + a.y += scale; b.y -= scale; + AddLine( a, b, colour ); + a = b = vx; + a.z += scale; b.z -= scale; + AddLine( a, b, colour ); +} + + +//============================================================================== +// DebugInfo::AddBox +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddBox(const rmt::Vector& a, const rmt::Vector& b, tColour colour) +{ + //Draw all 12 lines that make up the box + for(int i=0;i<4;i++) + { + AddLine(rmt::Vector((i&2)?a.x:b.x,(i&1)?a.y:b.y,a.z), + rmt::Vector((i&2)?a.x:b.x,(i&1)?a.y:b.y,b.z),colour); + AddLine(rmt::Vector((i&2)?a.x:b.x,a.y,(i&1)?a.z:b.z), + rmt::Vector((i&2)?a.x:b.x,b.y,(i&1)?a.z:b.z),colour); + AddLine(rmt::Vector(a.x,(i&2)?a.y:b.y,(i&1)?a.z:b.z), + rmt::Vector(b.x,(i&2)?a.y:b.y,(i&1)?a.z:b.z),colour); + } +} + + +//============================================================================== +// DebugInfo::AddBox +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddBox(const rmt::Vector ¢er, const float r, tColour colour) +{ + rmt::Vector a,b; + a.Sub(center, rmt::Vector(r,r,r)); + b.Add(center, rmt::Vector(r,r,r)); + + AddBox(a,b,colour); +} + + +//============================================================================== +// DebugInfo::AddCircle +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddCircle( const rmt::Vector& center, const float r, tColour colour ) +{ + rmt::Vector a,b; + int i; + int n = 8; + for( i = 0; i < n; i++ ) + { + a.x = center.x + r * rmt::Cos( i * rmt::PI_2 / n ); + a.y = center.y; + a.z = center.z + r * rmt::Sin( i * rmt::PI_2 / n ); + b.x = center.x + r * rmt::Cos( ( i + 1 ) * rmt::PI_2 / n ); + b.y = center.y; + b.z = center.z + r * rmt::Sin( ( i + 1 ) * rmt::PI_2 / n ); + AddLine( a, b, colour ); + } +} + + +//============================================================================== +// DebugInfo::AddText +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddText(const char *szName, const rmt::Vector &pos, tColour colour) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->AddText(szName, pos, colour); +} + + +//============================================================================== +// DebugInfo::AddScreenLine +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddScreenLine(const rmt::Vector& a, const rmt::Vector& b, tColour colour) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->AddScreenLine(a, b, colour); +} + + +//============================================================================== +// DebugInfo::AddScreenText +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddScreenText(const char* szName, tColour colour ) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->AddScreenText(szName, colour); +} + + +//============================================================================== +// DebugInfo::AddScreenText +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::AddScreenText(const char* szName, const rmt::Vector &a, tColour colour ) +{ + rAssert(_NumSection>0); + rAssert(_StackSize>0); + + _ppSections[_pStack[_StackSize-1]]->AddScreenText(szName, a,colour); +} + + +//============================================================================== +// DebugInfo::RenderBackground +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::RenderBackground() +{ + p3d::stack->Push(); + p3d::stack->LoadIdentity(); + pddiProjectionMode mode = p3d::pddi->GetProjectionMode(); + p3d::pddi->SetProjectionMode(PDDI_PROJECTION_DEVICE); + p3d::pddi->SetCullMode(PDDI_CULL_NONE); + + if( _shader == NULL ) + { + // + // init the shader + // + _shader = p3d::device->NewShader("simple"); + _shader->SetInt(PDDI_SP_SHADEMODE, PDDI_SHADE_FLAT); + } + _shader->SetInt(PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA); + + pddiPrimStream* stream = p3d::pddi->BeginPrims(_shader, PDDI_PRIM_TRIANGLES, PDDI_V_C, 6); + + float nearplane, farplane, fov, aspect; + p3d::pddi->GetCamera(&nearplane, &farplane, &fov, &aspect); + nearplane += 0.01f; + + float width, height; + width = (float)p3d::display->GetWidth(); + height = (float)p3d::display->GetHeight(); + pddiColour colour(0, 0, 0, 200); + + stream->Colour(colour); stream->Coord(0, height, nearplane); + stream->Colour(colour); stream->Coord(width, height, nearplane); + stream->Colour(colour); stream->Coord(width, 0, nearplane); + stream->Colour(colour); stream->Coord(0, height, nearplane); + stream->Colour(colour); stream->Coord(width, 0, nearplane); + stream->Colour(colour); stream->Coord(0, 0, nearplane); + + + p3d::pddi->EndPrims(stream); + + p3d::pddi->SetProjectionMode(mode); + p3d::stack->Pop(); +} + + +//============================================================================== +// DebugInfo::Render +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void DebugInfo::Render() +{ + //rAssert(_StackSize==0); + + // skip if disabled or no sections + if(! _isRenderEnabled) return; + if(_NumSection == 0) return; + + // this makes the text easier to read + if(_isBackgroundEnabled) RenderBackground(); + + // render the title with the name of the current section + char sectionName[255] = "DebugInfo : "; + Section *pSect = _ppSections[_CurrentSection]; + sprintf(sectionName, "DebugInfo : %s", pSect->GetName()); + p3d::pddi->DrawString(sectionName, 40, 50, tColour(0,255,255)); + + // render the current section + pSect->Render(); + + //Clear all the sections after we display + int i; + for(i=0;i<_NumSection;i++) + { + if(_ppSections[i]->GetAutoReset()) + { + _ppSections[i]->Reset(_ppSections[i]->GetName()); + } + } +} + +#endif // DEBUGINFO_ENABLED
\ No newline at end of file diff --git a/game/code/debug/debuginfo.h b/game/code/debug/debuginfo.h new file mode 100644 index 0000000..5c1b460 --- /dev/null +++ b/game/code/debug/debuginfo.h @@ -0,0 +1,204 @@ +//============================================================================== +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: debuginfo.h +// +// Description: In-game visual debug output +// +// History: 2002/07/02 + Migrated from Mirth -- Darwin Chau +// +//============================================================================== + +#ifndef DEBUGINFO_HPP +#define DEBUGINFO_HPP + + +// +// DebugInfo is only available in RAD_DEBUG and RAD_TUNE configurations +// +#ifndef RAD_RELEASE +#define DEBUGINFO_ENABLED +#endif // RAD_RELEASE + + + +#include "main/commandlineoptions.h" + + +//============================================================================== +// *** USE THESE MACROS, DO NOT INVOKE DEBUG INFO DIRECTLY *** +//============================================================================== + +#ifndef DEBUGINFO_ENABLED + +#define CREATE_DEBUGINFO() +#define DESTROY_DEBUGINFO() + +#define DEBUGINFO_PUSH_SECTION(s) +#define DEBUGINFO_POP_SECTION() + +#define DEBUGINFO_ADDSCREENTEXT(s) +#define DEBUGINFO_ADDSCREENTEXTVECTOR(s, v) +#define DEBUGINFO_ADDSCREENTEXTVECTORCOLOUR(s, v, c) +#define DEBUGINFO_ADDSCREENLINE(v1, v2, c) +#define DEBUGINFO_ADDLINE(v1, v2, c) +#define DEBUGINFO_ADDCIRCLE(v1, v2, c) +#define DEBUGINFO_ADDSTAR(v1, c, s) + +#define DEBUGINFO_TOGGLE(step) + +#define DEBUGINFO_RENDER(); + +#else + +#define CREATE_DEBUGINFO() if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::CreateInstance(); } +#define DESTROY_DEBUGINFO() if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::DestroyInstance(); } + +#define DEBUGINFO_PUSH_SECTION(s) (!CommandLineOptions::Get(CLO_FIREWIRE)) ? DebugInfo::GetInstance()->Push(s) : false +#define DEBUGINFO_POP_SECTION() if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->Pop(); } + +#define DEBUGINFO_ADDSCREENTEXT(s) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddScreenText(s); } +#define DEBUGINFO_ADDSCREENTEXTVECTOR(s, v) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddScreenText(s, v); } +#define DEBUGINFO_ADDSCREENTEXTVECTORCOLOUR(s, v, c) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddScreenText(s, v, c); } +#define DEBUGINFO_ADDSCREENLINE(v1, v2, c) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddScreenLine(v1, v2, c); } +#define DEBUGINFO_ADDLINE(v1, v2, c) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddLine(v1, v2, c); } +#define DEBUGINFO_ADDCIRCLE(v1, v2, c) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddCircle(v1, v2, c); } +#define DEBUGINFO_ADDSTAR(v1, c, s) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->AddStar(v1, c, s); } + +#define DEBUGINFO_TOGGLE(step) if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->Toggle(step); } + +#define DEBUGINFO_RENDER() if(!CommandLineOptions::Get(CLO_FIREWIRE)) { DebugInfo::GetInstance()->Render(); } + + +//======================================== +// Nested Includes +//======================================== +// Radmath +#include <radmath/radmath.hpp> +// Pure3D +#include <p3d/p3dtypes.hpp> +#include <pddi/pddi.hpp> + +//======================================== +// Forward References +//======================================== + +class tFont; +class tTypeFace; +class Section; + +//============================================================================== +// +// Synopsis: DebugInfo class provides visual debugging support. +// +//============================================================================== +class DebugInfo +{ +public: + /** get the singleton */ + static DebugInfo* GetInstance(); + + /** creates the singleton */ + static void CreateInstance(); + + /** destroys the instance */ + static void DestroyInstance(); + static void InitializeStaticVariables(); + + + /** Render */ + void Render(); + + /** Push a section */ + bool Push(char* szSection); + + /** Pop a section */ + void Pop(); + + /** Get the name of the last section pushed */ + const char* GetCurrentSection(); + + + //Toggle through the current sections + void Toggle(int step); + + //Debugging output functions, for world space primitives + void BeginSectionCreation() { _isCreationSectionOpen = true; }; + void EndSectionCreation() { _isCreationSectionOpen = false; }; + + /** make the section to resest automatically after the render */ + void SetAutoReset(bool autoreset); + + /** reset the current section + * @param sectionName the new name of the section + */ + void Reset(char* sectionName); + + void AddLine(const rmt::Vector &a, const rmt::Vector &b, tColour colour = tColour(255,255,255)); + void AddHVector(rmt::Vector o, rmt::Vector v, float h, tColour colour = tColour(255,255,255)); + void AddBox(const rmt::Vector &a, const rmt::Vector &b, tColour colour = tColour(255,255,255)); + void AddBox(const rmt::Vector ¢er, const float r, tColour colour = tColour(255,255,255)); + void AddCircle(const rmt::Vector ¢er, const float r, tColour colour = tColour(255,255,255)); + void AddStar(const rmt::Vector& vx, tColour colour = tColour(255,255,255), float scale = 0.1f); + void AddText(const char *szName, const rmt::Vector &pos, tColour colour = tColour(255,255,255)); + + //Output functions for screen space primitives + //All screen space is in x=[0..1], y=[0..1], with (0,0) at the top left + void AddScreenLine(const rmt::Vector &a, const rmt::Vector &b, tColour colour = tColour(255,255,255)); + void AddScreenText(const char* szName, tColour colour = tColour(255,255,255)); + void AddScreenText(const char* szName, const rmt::Vector &a, tColour colour = tColour(255,255,255)); + + // + // GUI events + // + void OnNext() { Toggle(1); }; + void OnSwitch(); + +protected: + void CreateNewSection( const char* section ); +private: + /** Constructor */ + DebugInfo(); + + /** Destructor */ + ~DebugInfo(); + + /** Render the backgound */ + void RenderBackground(); + + +// TODO: (chakib) do we need this ? +#if 1 + tFont* _pDebugFont; + tTypeFace* _pTypeFace; +#endif + + enum { MaxSections = 20 }; + int _NumSection; + Section* _ppSections[MaxSections]; + + enum { MaxStackSize = 20 }; + int _StackSize; + int _pStack[MaxStackSize]; + + int _CurrentSection; + + float _DebugMenuTime; + + static DebugInfo* _Instance; + + bool _isRenderEnabled; + bool _isBackgroundEnabled; + bool _isCreationSectionOpen; + + enum Mode {OFF, BACKGROUND, NOBACKGROUND, MODE_MAX}; + Mode _mode; + + pddiShader* _shader; //@- used the render the background +}; + + +#endif // ! DEBUGINFO_ENABLED + +#endif // DEBUGINFO_HPP + diff --git a/game/code/debug/profiler.cpp b/game/code/debug/profiler.cpp new file mode 100644 index 0000000..cb2949c --- /dev/null +++ b/game/code/debug/profiler.cpp @@ -0,0 +1,753 @@ +//=========================================================================== +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// Component: PS2Platform +// +// Description: Abstracts the differences for setting up and shutting down +// the different platforms. +// +// History: + Stolen and cleaned up from Penthouse -- Darwin Chau +// +//=========================================================================== + +//======================================== +// System Includes +//======================================== +// Libraries +#include <string.h> +#include <stdio.h> +// Foundation +#include <radtime.hpp> +#include <raddebug.hpp> +#include <raddebugwatch.hpp> +// Pure3D +#include <pddi/pddi.hpp> +#include <p3d/p3dtypes.hpp> +#include <p3d/utility.hpp> + +//======================================== +// Project Includes +//======================================== +#include <debug/profiler.h> +#include <memory/srrmemory.h> + + +#ifdef PROFILER_ENABLED + +//****************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//****************************************************************************** + +// Static pointer to instance of singleton. +Profiler* Profiler::spInstance = NULL; + +int Profiler::sRed = 0; +int Profiler::sGreen = 0; +int Profiler::sBlue = 0; +int Profiler::sPage = 0; +int Profiler::sLeftOffset = 0; +int Profiler::sTopOffset = 0; +bool Profiler::sDisplay = false; +bool Profiler::sDumpToOutput = false; +bool Profiler::sEnableCollection = false; + + +//****************************************************************************** +// +// Public Member Functions +// +//****************************************************************************** + +//============================================================================== +// Profiler::CreateInstance +//============================================================================== +// +// Description: Creates the Profiler. +// +// Parameters: None. +// +// Return: Pointer to the Profiler. +// +// Constraints: This is a singleton so only one instance is allowed. +// +//============================================================================== +Profiler* Profiler::CreateInstance() +{ +MEMTRACK_PUSH_GROUP( "Profiler" ); + rAssert( spInstance == NULL ); + + spInstance = new(GMA_DEBUG) Profiler; + rAssert( spInstance ); +MEMTRACK_POP_GROUP( "Profiler" ); + + return spInstance; +} + +//============================================================================== +// Profiler::GetInstance +//============================================================================== +// +// Description: - Access point for the Profiler singleton. +// +// Parameters: None. +// +// Return: Pointer to the Profiler. +// +// Constraints: This is a singleton so only one instance is allowed. +// +//============================================================================== +Profiler* Profiler::GetInstance() +{ + rAssert( spInstance != NULL ); + + return spInstance; +} + + +//============================================================================== +// Profiler::DestroyInstance +//============================================================================== +// +// Description: Destroy the Profiler. +// +// Parameters: None. +// +// Return: None. +// +//============================================================================== +void Profiler::DestroyInstance() +{ + rAssert( spInstance != NULL ); + + delete( GMA_DEBUG, spInstance ); + spInstance = NULL; +} + + + +//============================================================================== +// Profiler::Init +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::Init() +{ +} + + + +//============================================================================== +// Profiler::AllocSample +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: the next available sample or NULL +// +//============================================================================== +Profiler::ProfileSample *Profiler::AllocSample(void) +{ + if (mNextSampleAllocIndex >= NUM_SAMPLES) return NULL; + + return &mSamples[mNextSampleAllocIndex++]; +} + +//============================================================================== +// Profiler::AllocHistory +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: the next available history or NULL +// +//============================================================================== +Profiler::ProfileSampleHistory *Profiler::AllocHistory(void) +{ + if (mNextHistoryAllocIndex >= NUM_SAMPLES) return NULL; + + return &mHistory[mNextHistoryAllocIndex++]; +} + +//============================================================================== +// Profiler::BeginFrame +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::BeginFrame() +{ + int i; + for( i = 0; i < NUM_SAMPLES; ++i ) + { + mSamples[i].bValid = false; + } + + mOpenStackTop = -1; + mNextSampleAllocIndex = 0; + + mStartProfile = ((float)radTimeGetMicroseconds()) / 1000.0F; + + mOpenSampleStore->RemoveAll(); + + // + // Only collect profile data if we're actually going to show it on the screen. + // Check it here so that we don't turn it on/off in mid-sample. + // + sEnableCollection = sDisplay; +} + + +//============================================================================== +// Profiler::EndFrame +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::EndFrame() +{ + unsigned int i = 0; + + if( !sEnableCollection ) + { + return; + } + + mEndProfile = ((float)radTimeGetMicroseconds()) / 1000.0F; + + while( i < mNextSampleAllocIndex) + { + if (!mSamples[i].bValid) continue; + float sampleTime, percentTime; + + rAssertMsg(!mSamples[i].isOpen, "ProfileEnd() called without a ProfileBegin()" ); + + sampleTime = mSamples[i].fAccumulator - mSamples[i].fChildrenSampleTime; + + float profileTime = mEndProfile - mStartProfile; + + if( profileTime < 0.001F ) + { + percentTime = 0.0f; + } + else + { + percentTime = ( sampleTime / profileTime ) * 100.0f; + rAssert( percentTime <= 100.0f ); + } + + // + // Add new measurement into the history and get the ave, min, and max + // +// this->StoreProfileHistory( mSamples[i].szName, +// percentTime, +// mEndProfile - mStartProfile, +// mSamples[i].uiSampleTime, // single sample +// mSamples[i].uiAccumulator ); // total sample + this->StoreProfileHistory( mSamples[i].uid, + percentTime, + profileTime, + mSamples[i].fSampleTime, // single sample + mSamples[i].fAccumulator ); // total sample + i++; + } +} + + +//============================================================================== +// Profiler::BeginProfile +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::BeginProfile( const char* name ) +{ + int i; + tUID nameUID; + + if( !sEnableCollection ) + { + return; + } + + i = 0; + nameUID = tEntity::MakeUID( name ); + + // If the sample is alread open this frame it will be in the store + ProfileSample *sample = mOpenSampleStore->Find(nameUID); + + // Sample isn't in the store. Alloc a new one, set it up, and store it + if (sample == NULL) + { + sample = AllocSample(); + rAssertMsg(sample != NULL, "Exceeded Maximum Available Profile Samples." ); + + sample->bValid = true; + sample->uid = nameUID; + sample->iProfileInstances = 0; + sample->fAccumulator = 0.0F; + sample->fChildrenSampleTime = 0.0F; + sample->fSampleTime = 0.0F; + sample->fTotalTime = 0.0F; + sample->iNumParents = 0; + sample->isOpen = false; + + strncpy(sample->szName, name, 255); + + mOpenSampleStore->Store(nameUID, sample); + } + + rAssertMsg(!sample->isOpen, "Profiler section error: Started a second time without closing."); + + sample->iProfileInstances++; + sample->isOpen = true; + sample->fStartTime = ((float)radTimeGetMicroseconds()) / 1000.0F; + + // Ahh, pointer math. + unsigned sampleIndex = sample - mSamples; + + // Add this sample to the open stack + rAssertMsg(mOpenStackTop < (MAX_PROFILER_DEPTH - 1), "Profiler error: Too many levels deep."); + ++mOpenStackTop; + mOpenStack[mOpenStackTop] = sampleIndex; +} + + +//============================================================================== +// Profiler::EndProfile +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::EndProfile( const char* name ) +{ + tUID nameUID; + + if( !sEnableCollection ) + { + return; + } + + nameUID = tEntity::MakeUID( name ); + + ProfileSample *sample = mOpenSampleStore->Find(nameUID); + rAssertMsg(sample != NULL, "Profiler error: Ending a section that isn't open."); + rAssertMsg(sample->isOpen, "Profiler error: Ending a section that isn't open."); + + float endTime = ((float)radTimeGetMicroseconds()) / 1000.0F; + float duration = endTime - sample->fStartTime; + + sample->isOpen = false; + sample->iNumParents = mOpenStackTop; + sample->fAccumulator += duration; + sample->fSampleTime = duration; + + // Pop the stack + mOpenStackTop--; + + // Only update the parent if there is one + if (mOpenStackTop > 0) + { + unsigned int parentIndex = mOpenStack[mOpenStackTop]; + mSamples[parentIndex].fChildrenSampleTime += duration; + } +} + + + +//============================================================================== +// Profiler::Render +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::Render(void) +{ + const int LEFT = 10; + const int TOP = 45; + + if( !sDisplay ) + { + return; + } + + //int i = mScrollCount * NUM_VISIBLE_LINES; + unsigned int i = sPage * NUM_VISIBLE_LINES; + + if( sDumpToOutput ) + { + i = 0; + } + + float startTime = ((float)radTimeGetMicroseconds()) / 1000.0F; + + BEGIN_PROFILE("* Render Profile *") + + // + // Display header info. + // + char fps[256]; + sprintf(fps,"Game Time: %3.1f(fps) : %3.1f(ms) Adjusted Time: %3.1f(fps) : %3.1f(ms)", 1/(mFrameRate/1000), mFrameRate, 1/(mFrameRateAdjusted/1000), mFrameRateAdjusted); + +// const int SHADOW_OFFSET = 1; +// tColour SHADOW_COLOUR(0,0,0); + tColour stringColour = tColour(sRed, sGreen, sBlue); +/* + p3d::pddi->DrawString( fps, + LEFT + sLeftOffset + SHADOW_OFFSET, + TOP + sTopOffset + SHADOW_OFFSET, + SHADOW_COLOUR ); + + p3d::pddi->DrawString( "-------------------------------------------------------------------", + LEFT + sLeftOffset + SHADOW_OFFSET, + 20 + TOP + sTopOffset + SHADOW_OFFSET, + SHADOW_COLOUR); + + p3d::pddi->DrawString( "Ave(%)\t| Single\t| #\t| Total\t| Profile Name\n", + LEFT + sLeftOffset + SHADOW_OFFSET, + 40 + TOP + sTopOffset + SHADOW_OFFSET, + SHADOW_COLOUR ); + + p3d::pddi->DrawString( "-------------------------------------------------------------------", + LEFT + sLeftOffset + SHADOW_OFFSET, + 60 + TOP + sTopOffset + SHADOW_OFFSET, + SHADOW_COLOUR); +*/ + + + p3d::pddi->DrawString( fps, + LEFT + sLeftOffset, + TOP + sTopOffset, + stringColour); + + p3d::pddi->DrawString( "-------------------------------------------------------------------", + LEFT + sLeftOffset, + 20 + TOP + sTopOffset, + stringColour ); + + p3d::pddi->DrawString( "Ave(%)\t| Single\t| #\t| Total\t| Profile Name\n", + LEFT + sLeftOffset, + 40 + TOP + sTopOffset, + stringColour ); + + p3d::pddi->DrawString( "-------------------------------------------------------------------", + LEFT + sLeftOffset, + 60 + TOP + sTopOffset, + stringColour ); + + if( sDumpToOutput ) + { + rTuneString( "-------------------------------------------------------------------------------\n" ); + rTuneString( "Ave(%)\t| Single\t| #\t| Total\t| Profile Name\n" ); + rTuneString( "-------------------------------------------------------------------------------\n" ); + } + + while( (i < mNextSampleAllocIndex) && mSamples[i].bValid ) + { + unsigned int indent = 0; + float aveTime, minTime, maxTime, sampleAve, totalTime; + char line[256], name[256], indentedName[256]; + char ave[32], min[32], max[32], num[32], sample[32], total[32]; + +// this->GetProfileHistory( mSamples[i].szName, &aveTime, &minTime, &maxTime, &sampleAve, &totalTime); + this->GetProfileHistory( mSamples[i].uid, &aveTime, &minTime, &maxTime, &sampleAve, &totalTime); + + + // Format the data + sprintf( ave, "%3.2f", aveTime ); + sprintf( min, "%3.2f", minTime ); + sprintf( max, "%3.2f", maxTime ); + sprintf( sample,"%3.2f", sampleAve ); + sprintf( num, "%3d", mSamples[i].iProfileInstances ); + sprintf( total, "%3.2f", totalTime ); + + + strcpy( indentedName, mSamples[i].szName ); + + + for( indent=0; indent<mSamples[i].iNumParents; indent++ ) + { + sprintf( name, " %s", indentedName ); + strcpy( indentedName, name ); + } + sprintf(line,"%5s\t| %5s\t|%2s\t| %5s\t| %s ", ave, sample, num, total, indentedName); + +// p3d::pddi->DrawString( line, +// LEFT + sLeftOffset + SHADOW_OFFSET, +// 80 + TOP + ((i % NUM_VISIBLE_LINES)*20) + sTopOffset + SHADOW_OFFSET, +// SHADOW_COLOUR); + + p3d::pddi->DrawString( line, + LEFT + sLeftOffset, + 80 + TOP + ((i % NUM_VISIBLE_LINES)*20) + sTopOffset, + stringColour); + + if( sDumpToOutput ) + { + rTunePrintf( "%s\n", line ); + } + + i++; + + if( i >= (unsigned int) (( sPage + 1 ) * NUM_VISIBLE_LINES )) + { + break; + } + } + + END_PROFILE("* Render Profile *") + + mDisplayTime = (((float)radTimeGetMicroseconds()) / 1000.0F) - startTime; + + sDumpToOutput = false; +} + + +//============================================================================== +// Profiler::Next +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::NextPage() +{ + ++sPage; + + if( sPage == NUM_VISIBLE_PANES ) + { + sPage = 0; + } +} + + +//****************************************************************************** +// +// Private Member Functions +// +//****************************************************************************** + +//============================================================================== +// Profiler::Profiler +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//==============================================================================// +Profiler::Profiler() : + mOpenStackTop( -1 ), + mStartProfile( 0.0F ), + mEndProfile( 0.0F ), + mFrameRate( 0.0f ), + mFrameRateAdjusted( 0.0f ), + mDisplayTime( 0.0F ), + mNextHistoryAllocIndex( 0 ) +{ + int i; + for( i = 0; i < NUM_SAMPLES; ++i ) + { + mSamples[i].bValid = false; + mSamples[i].iNumParents = 0; + } + +MEMTRACK_PUSH_GROUP( "Profiler" ); + + HeapMgr()->PushHeap( GMA_DEBUG ); + + mOpenSampleStore = new HashTable<ProfileSample>(NUM_SAMPLES * 2, 100, NUM_SAMPLES * 2); + mOpenHistoryStore = new HashTable<ProfileSampleHistory>(NUM_SAMPLES * 2, 100, NUM_SAMPLES * 2); + + mOpenSampleStore->AddRef(); + mOpenHistoryStore->AddRef(); + + HeapMgr()->PopHeap( GMA_DEBUG ); + +MEMTRACK_POP_GROUP( "Profiler" ); + + radDbgWatchAddBoolean( &sDisplay, "Display", "Profiler", 0, 0 ); + radDbgWatchAddInt( &sPage, "Select Page", "Profiler", 0, 0, 0, NUM_VISIBLE_PANES ); + radDbgWatchAddInt( &sLeftOffset, "Left Position", "Profiler", 0, 0, -1000, 1000 ); + radDbgWatchAddInt( &sTopOffset, "Top Position", "Profiler", 0, 0, -1000, 1000 ); + radDbgWatchAddInt( &sRed, "Text Colour - Red", "Profiler", 0, 0, 0, 255 ); + radDbgWatchAddInt( &sGreen, "Text Colour - Green", "Profiler", 0, 0, 0, 255 ); + radDbgWatchAddInt( &sBlue, "Text Colour - Blue", "Profiler", 0, 0, 0, 255 ); + radDbgWatchAddBoolean( &sDumpToOutput, "Dump to Output Window", "Profiler", 0, 0 ); +} + + +//============================================================================== +// Profiler::~Profiler +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//==============================================================================// +Profiler::~Profiler() +{ +} + + +//============================================================================== +// Profiler::StoreProfileHistory +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::StoreProfileHistory +( +// char* name, + tUID nameUID, + float percent, + float elapsedTime, + float sampleTime, + float totalTime +) +{ + float oldRatio; + float newRatio = 0.8f * (elapsedTime / 1000.0f); + + if( newRatio > 1.0f ) + { + newRatio = 1.0f; + } + oldRatio = 1.0f - newRatio; + + mFrameRate = (mFrameRate * oldRatio) + (elapsedTime * newRatio); + + // TODO: I had to put this in because there are cases where elapsedTime + // is 0 and mDisplayTime isn't... How can that happen? + // + float adjustedTime = 0.0F; + + if( elapsedTime >= mDisplayTime ) + { + adjustedTime = elapsedTime - mDisplayTime; + } + + mFrameRateAdjusted = (mFrameRateAdjusted*oldRatio) + (adjustedTime * newRatio); + + ProfileSampleHistory *history = mOpenHistoryStore->Find(nameUID); + if (history == NULL) + { + history = AllocHistory(); + rAssertMsg(history != NULL, "Too many profiler histories."); + + history->uid = nameUID; + history->fAve = percent; + history->fMin = percent; + history->fMax = percent; + history->fSampleAve = sampleTime; + history->fSampleTotal = totalTime; + + mOpenHistoryStore->Store(nameUID, history); + } + else + { + history->fAve = (history->fAve * oldRatio) + (percent * newRatio); + history->fSampleAve = (history->fSampleAve * oldRatio) + (sampleTime * newRatio); + history->fSampleTotal = (history->fSampleTotal * oldRatio) + (totalTime * newRatio); + + if( percent < history->fMin ) history->fMin = percent; + else history->fMin = (history->fMin * oldRatio) + (percent * newRatio); + + if( history->fMin < 0.0f ) history->fMin = 0.0f; + + if( percent > history->fMax ) history->fMax = percent; + else history->fMax = (history->fMax * oldRatio) + (percent * newRatio); + } + +} + + +//============================================================================== +// Profiler::GetProfileHistory +//============================================================================== +// +// Description: +// +// Parameters: +// +// Return: +// +//============================================================================== +void Profiler::GetProfileHistory +( +// char* name, + tUID nameUID, + float* ave, + float* min, + float* max, + float* sample, + float* total +) +{ + *ave = *min = *max = *sample = 0.0f; + + ProfileSampleHistory *history = mOpenHistoryStore->Find(nameUID); + //rAssertMsg(history != NULL, "Get Profile history Error: Never been stored!"); + + if (history != NULL) + { + *ave = history->fAve; + *min = history->fMin; + *max = history->fMax; + *sample = history->fSampleAve; + *total = history->fSampleTotal; + } +} + + +#endif // PROFILER_ENABLED
\ No newline at end of file diff --git a/game/code/debug/profiler.h b/game/code/debug/profiler.h new file mode 100644 index 0000000..ba61ff1 --- /dev/null +++ b/game/code/debug/profiler.h @@ -0,0 +1,206 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: profiler.h +// +// Description: In-game profiler. +// +// History: 5/8/2002 + Migrated from SRR -- Darwin Chau +// +//============================================================================= + +#ifndef PROFILER_H +#define PROFILER_H + +//======================================== +// Nested Includes +//======================================== + +//======================================== +// Forward References +//======================================== + +#if !defined( RAD_RELEASE ) && !defined( WORLD_BUILDER ) && !defined( RAD_MW ) && !defined( RAD_WIN32 ) + #define PROFILER_ENABLED +#endif // RAD_RELEASE + + +#include "main/commandlineoptions.h" + +#include <p3d/entity.hpp> +#include <radload/utility/hashtable.hpp> + +//=========================================================================== +// *** USE THESE MACROS, DO NOT INVOKE PROFILER DIRECTLY *** +//=========================================================================== + + +#ifndef PROFILER_ENABLED + + #define CREATE_PROFILER() + #define DESTROY_PROFILER() + + #define BEGIN_PROFILE(string) + #define END_PROFILE(string) + + #define BEGIN_PROFILER_FRAME() + #define END_PROFILER_FRAME() + + #define RENDER_PROFILER() + + #define SNSTART(id, txt) + #define SNSTOP(id) + +#else + +#ifdef SNTUNER +#include <SNTuner.h> + #define SNSTART(id, txt) snStartMarker(id, txt) + #define SNSTOP(id) snStopMarker(id); +#endif + + #define CREATE_PROFILER() if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { Profiler::CreateInstance(); } + #define DESTROY_PROFILER() if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { Profiler::DestroyInstance(); } + + #define BEGIN_PROFILE(string) if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { GetProfiler()->BeginProfile(string); } + #define END_PROFILE(string) if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { GetProfiler()->EndProfile(string); } + + #define BEGIN_PROFILER_FRAME() if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { GetProfiler()->BeginFrame(); } + #define END_PROFILER_FRAME() if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { GetProfiler()->EndFrame(); } + + #define RENDER_PROFILER() if(!(CommandLineOptions::Get(CLO_DESIGNER) || CommandLineOptions::Get(CLO_FIREWIRE))) { GetProfiler()->Render(); } + + +#define MAX_PROFILER_DEPTH 32 + +//=========================================================================== +// +// Description: Generally, describe what behaviour this class possesses that +// clients can rely on, and the actions that this service +// guarantees to clients. +// +// Constraints: Describe here what you require of the client which uses or +// has this class - essentially, the converse of the description +// above. A constraint is an expression of some semantic +// condition that must be preserved, an invariant of a class or +// relationship that must be preserved while the system is in a +// steady state. +// +//=========================================================================== +class Profiler +{ + public: + + static Profiler* CreateInstance(); + static Profiler* GetInstance(); + static void DestroyInstance(); + + void Init(); + + void BeginProfile( const char* name ); + void EndProfile( const char* name ); + + void BeginFrame(); + void EndFrame(); + + void ToggleDisplay() { sDisplay = !sDisplay; } + void NextPage(); + + void Render(); + + // + // Watcher tunable + // + static int sRed; + static int sGreen; + static int sBlue; + static int sPage; + static int sLeftOffset; + static int sTopOffset; + static bool sDisplay; + static bool sDumpToOutput; + + private: + + + Profiler(); + ~Profiler(); + + + void StoreProfileHistory( tUID nameUID, + float percent, + float elapsedTime, + float sampleTime, + float totalTime ); + + void GetProfileHistory( tUID nameUID, + float* ave, + float* min, + float* max , + float* sample, + float* total ); + struct ProfileSample + { + bool bValid; // Whether the data is valid + tUID uid; // Hashed name for comparisons. + unsigned int iProfileInstances; // # of times ProfileBegin called + float fStartTime; // The current open profile start time + float fAccumulator; // All samples this frame added together + float fChildrenSampleTime; // Time taken by all children + float fSampleTime; // Time for a single pass + float fTotalTime; // Time for all passess + unsigned int iNumParents; // Number of profile parents + bool isOpen; // Is the profile section open? + char szName[256]; // Name of sample + }; + + struct ProfileSampleHistory + { + tUID uid; //Hased name for comparisons + float fAve; //Average time per frame (percentage) + float fMin; //Minimum time per frame (percentage) + float fMax; //Maximum time per frame (percentage) + float fSampleAve; + float fSampleTotal; + }; + + static Profiler* spInstance; + + ProfileSample *AllocSample(void); + ProfileSampleHistory *AllocHistory(void); + + enum + { + NUM_SAMPLES = 256, // Must be power of two for hash table + NUM_VISIBLE_LINES = 15, + NUM_VISIBLE_PANES = 1 + ((NUM_SAMPLES-1) / NUM_VISIBLE_LINES ) + }; + + HashTable<ProfileSample> *mOpenSampleStore; + HashTable<ProfileSampleHistory> *mOpenHistoryStore; + + ProfileSample mSamples[NUM_SAMPLES]; + ProfileSampleHistory mHistory[NUM_SAMPLES]; + + unsigned int mOpenStack[MAX_PROFILER_DEPTH]; + int mOpenStackTop; + + float mStartProfile; + float mEndProfile; + + float mFrameRate; + float mFrameRateAdjusted; + + float mDisplayTime; + unsigned int mNextSampleAllocIndex; + unsigned int mNextHistoryAllocIndex; + + static bool sEnableCollection; +}; + +// A little syntactic sugar for getting at this singleton. +inline Profiler* GetProfiler() { return( Profiler::GetInstance() ); } + +#endif // PROFILER_ENABLED + +#endif // PROFILER_H
\ No newline at end of file diff --git a/game/code/debug/ps2perf.hpp b/game/code/debug/ps2perf.hpp new file mode 100644 index 0000000..562b4bf --- /dev/null +++ b/game/code/debug/ps2perf.hpp @@ -0,0 +1,263 @@ +// Performance counter class for PS2 +// Nov 2001 - Amit Bakshi + +#ifndef PS2PERF_HPP +#define PS2PERF_HPP + +/************************************************************************************/ +// nov6/2001 amb - Performance Counter class +// based on David Coombes' (david_coombes@playstation.sony.com) code +// sample usage : +// +// void TestSinCos() +// { +// ps2Perf perf("mySinCos"); +// +// for(int i =0; i < 16; i++) +// { +// perf.StartSample(); +// +// float s,c; +// mySinCos( i, &s , &c ); +// +// perf.EndSample(); +// } +// perf.PrintStats(); +// }; +/************************************************************************************/ + +#define ClocksToMs 294912 + +inline unsigned int GetCycleCounter(void) +{ + unsigned int ret; + asm __volatile__ ("mfc0 %0,$9" : "=r" (ret) ); + return ret; +} + +// amb nov6/2001 - caution : do not call in middle of the code, +// it'll mess up PDDI stats +inline void ResetCycleCounter(void) +{ + asm __volatile__ ("mtc0 $0,$9 "); +}; + + +class ps2Perf +{ +public: + + ps2Perf(const char* what) + { + strncpy( desc,what,sizeof(desc)-1); + Reset(); + }; + + ~ps2Perf() + { + asm __volatile__ ("mtps $0,0"); + }; + + inline void Reset() + { + count = 0; + for(int i = 0; i < PC0_NO_EVENT; i++) + { + pc0[i].min = pc1[i].min = 0xffff; + pc0[i].max = pc1[i].max = 0; + pc0[i].cur = pc1[i].cur = 0; + pc0[i].tot = pc1[i].tot = 0; + pc0[i].num = pc1[i].num = 0; + } + } + + inline void BeginSample() + { + int evt = count % PC0_NO_EVENT; + BeginSample(evt); + }; + + inline void BeginSample(int evt) + { + pccr.cl0 = 0x8; // only user mode + pccr.event0 = evt; + pccr.cl1 = 0x8; + pccr.event1 = evt; + pccr.cte = 1; + + int hack = *((int*)(&pccr)); + + asm __volatile__(" + .set noreorder + .set noat + mtps $0,0 # halt performance counters + sync.p # + mtpc $0,0 # set perfcounter 0 to zero + mtpc $0,1 # set perfcounter 1 to zero + sync.p # + mtps %0,0 # truly - we rule ( well stewart does anyway...) + .set reorder + .set at + " + : // no output + : "r"(hack) + ); + } + inline void EndSample() + { + int evt = count % PC0_NO_EVENT; + EndSample(evt); + count++; + }; + + inline void EndSample(int evt) + { + register unsigned int ret_pc0=0; + register unsigned int ret_pc1=0; + + asm __volatile__(" + .set noreorder + .set noat + mfpc %0,0 + mfpc %1,1 + .set reorder + .set at + ":"=r"(ret_pc0),"=r"(ret_pc1)); + + if(ret_pc0<pc0[evt].min) pc0[evt].min = ret_pc0; + if(ret_pc0>pc0[evt].max) pc0[evt].max = ret_pc0; + pc0[evt].cur = ret_pc0; + pc0[evt].tot+= ret_pc0; + pc0[evt].num++; + + if(ret_pc1<pc1[evt].min) pc1[evt].min = ret_pc1; + if(ret_pc1>pc1[evt].max) pc1[evt].max = ret_pc1; + pc1[evt].cur = ret_pc1; + pc1[evt].tot+= ret_pc1; + pc1[evt].num++; + + asm __volatile__ ("mtps $0,0"); + }; + + inline void StopCounters() + { + asm __volatile__ ("mtps $0,0"); + } + + void PrintStats() + { + #define PRINT_STAT_0(desc,i) if (pc0[i].num) printf(desc "%6d, %6d, %6d, %6d\n",pc0[i].min, pc0[i].max, pc0[i].cur, pc0[i].tot/pc0[i].num); + #define PRINT_STAT_1(desc,i) if (pc1[i].num) printf(desc "%6d, %6d, %6d, %6d\n",pc1[i].min, pc1[i].max, pc1[i].cur, pc1[i].tot/pc1[i].num); + + printf("==== %s ====(total iterations)%d (per event)%d (frame%%) ===========\n",desc,count,(count/PC0_NO_EVENT)); + printf("Event , min, max, cur, ave \n"); + + PRINT_STAT_0("Processor cycle ,", 1 ); + PRINT_STAT_0("Single instructions issue ,", 2 ); + PRINT_STAT_0("Branch issued ,", 3 ); + PRINT_STAT_0("BTAC miss ,", 4 ); + PRINT_STAT_0("ITLB miss ,", 5 ); + PRINT_STAT_0("Instruction cache miss ,", 6 ); + PRINT_STAT_0("DTLB accessed ,", 7 ); + PRINT_STAT_0("Non-blocking load ,", 8 ); + PRINT_STAT_0("WBB single request ,", 9 ); + PRINT_STAT_0("WBB burst request ,",10 ); + PRINT_STAT_0("CPU address bus busy ,",11 ); + PRINT_STAT_0("Instruction completed ,",12 ); + PRINT_STAT_0("Non-BDS instruction completed ,",13 ); + PRINT_STAT_0("COP2 instruction completed ,",14 ); + PRINT_STAT_0("Load completed ,",15 ); + + PRINT_STAT_1("Low-order branch issued ,", 0 ); + PRINT_STAT_1("Processor cycle ,", 1 ); + PRINT_STAT_1("Dual instructions issue ,", 2 ); + PRINT_STAT_1("Branch miss-predicted ,", 3 ); + PRINT_STAT_1("TLB miss ,", 4 ); + PRINT_STAT_1("DTLB miss ,", 5 ); + PRINT_STAT_1("Data cache miss ,", 6 ); + PRINT_STAT_1("WBB single request unavailable,", 7 ); + PRINT_STAT_1("WBB burst request unavailable ,", 8 ); + PRINT_STAT_1("WBB burst request almost full ,", 9 ); + PRINT_STAT_1("WBB burst request full ,",10 ); + PRINT_STAT_1("CPU data bus busy ,",11 ); + PRINT_STAT_1("Instruction completed ,",12 ); + PRINT_STAT_1("Non-BDS instruction completed ,",13 ); + PRINT_STAT_1("COP1 instruction completed ,",14 ); + PRINT_STAT_1("Store completed ,",15 ); + + #undef PRINT_STAT_0 + #undef PRINT_STAT_1 + + } + +private: + enum PCOUNT0_EVENT // Performance Counter 0 Events + { + PC0_RESERVED =(0 ), + PC0_CPU_CYCLE =(1 ), // Processor cycle + PC0_SINGLE_ISSUE =(2 ), // Single instructions issue + PC0_BRANCH_ISSUED =(3 ), // Branch issued + PC0_BTAC_MISS =(4 ), // BTAC miss + PC0_ITLB_MISS =(5 ), // ITLB miss + PC0_ICACHE_MISS =(6 ), // Instruction cache miss + PC0_DTLB_ACCESSED =(7 ), // DTLB accessed + PC0_NONBLOCK_LOAD =(8 ), // Non-blocking load + PC0_WBB_SINGLE_REQ =(9 ), // WBB single request + PC0_WBB_BURST_REQ =(10), // WBB burst request + PC0_ADDR_BUS_BUSY =(11), // CPU address bus busy + PC0_INST_COMP =(12), // Instruction completed + PC0_NON_BDS_COMP =(13), // Non-BDS instruction completed + PC0_COP2_COMP =(14), // COP2 instruction completed + PC0_LOAD_COMP =(15), // Load completed + PC0_NO_EVENT =(16) // No event + }; + + enum PCOUNT1_EVENT // Performance Counter 1 Events + { + PC1_LOW_BRANCH_ISSUED =(0 ), // Low-order branch issued + PC1_CPU_CYCLE =(1 ), // Processor cycle + PC1_DUAL_ISSUE =(2 ), // Dual instructions issue + PC1_BRANCH_MISS_PREDICT =(3 ), // Branch miss-predicted + PC1_TLB_MISS =(4 ), // TLB miss + PC1_DTLB_MISS =(5 ), // DTLB miss + PC1_DCACHE_MISS =(6 ), // Data cache miss + PC1_WBB_SINGLE_UNAVAIL =(7 ), // WBB single request unavailable + PC1_WBB_BURST_UNAVAIL =(8 ), // WBB burst request unavailable + PC1_WBB_BURST_ALMOST =(9 ), // WBB burst request almost full + PC1_WBB_BURST_FULL =(10), // WBB burst request full + PC1_DATA_BUS_BUSY =(11), // CPU data bus busy + PC1_INST_COMP =(12), // Instruction completed + PC1_NON_BDS_COMP =(13), // Non-BDS instruction completed + PC1_COP1_COMP =(14), // COP1 instruction completed + PC1_STORE_COMP =(15), // Store completed + PC1_NO_EVENT =(16) // No event + }; + + struct count_t + { + unsigned int min,max,tot,cur,num; + }; + + // nov6/2001 amb - see p82 EE Core User's Manual 4.0 + struct pccr_t + { + unsigned pad0:1; // unused + unsigned cl0:4; // events in which mode (eg user/kernel/super/exception) + unsigned event0:5; // event to count in counter 0 (see PCOUNT0_EVENT) + unsigned pad1:1; // unused + unsigned cl1:4; // events in which mode (eg user/kernel/super/exception) + unsigned event1:5; // event to count in counter 1 (see PCOUNT1_EVENT) + unsigned pad2:11; // unused + unsigned cte:1; // counter enable + }; + + char desc[32]; + + pccr_t pccr; // 16 events + + count_t pc0[PC0_NO_EVENT]; + count_t pc1[PC0_NO_EVENT]; + unsigned int count; +}; + +#endif // PS2PERF_HPP diff --git a/game/code/debug/section.cpp b/game/code/debug/section.cpp new file mode 100644 index 0000000..d87379e --- /dev/null +++ b/game/code/debug/section.cpp @@ -0,0 +1,236 @@ +#include <debug/section.h> +#include <p3d/matrixstack.hpp> +#include <p3d/utility.hpp> + +Section::Section(tFont* pFont, const char* szName) : + _pDebugFont(pFont), + _pLineShader(NULL), + _autoReset(true) +{ + assert(szName); + + int i; + + Reset(szName); + + _pLineShader = p3d::device->NewShader(/*p3d::pddi, */"simple"); + _pLineShader->AddRef(); + _pLineShader->SetInt(PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA); + + //Allocate string primitives for the 3d strings + for(i=0;i<MaxText;i++) + { + if(_pDebugFont) + { + _pDebugFont->AddRef(); + + P3D_UNICODE string[256]; + char emptyString[] = "Empty String"; + p3d::AsciiToUnicode(emptyString, string, strlen(emptyString)); + + _pText[i]._pText = new tTextString(_pDebugFont, string); + _pText[i]._pText->AddRef(); + } + else + { + _pText[i]._pText = NULL; + } + } +} +Section::~Section() +{ + for(int i=0;i<MaxText;i++) + { + tRefCounted::Release(_pText[i]._pText); + } + + tRefCounted::Release(_pLineShader); + tRefCounted::Release(_pDebugFont); +} + +void Section::Reset(const char *szName) +{ + assert(szName); + strncpy(_szName, szName, sizeof(_szName)); + + _NumLines = _NumText = _NumScreenLines = _NumScreenText = 0; + ClearScreenText(); +} + +const char* Section::GetName() const +{ + + return _szName; +} + +void Section::AddLine(const rmt::Vector& a, const rmt::Vector& b, tColour colour/*, float time*/) +{ + if(_NumLines < MaxLines) + { + _Lines[_NumLines]._a = a; + _Lines[_NumLines]._b = b; + _Lines[_NumLines]._Colour = colour; + _NumLines++; + } +} + +void Section::AddText(const char *szName, const rmt::Vector &pos, tColour colour/*, float time = 0*/) +{ + assert(szName); + if(_NumText < MaxText && _pText[_NumText]._pText) + { + tTextString* p = _pText[_NumText]._pText; + + P3D_UNICODE string[256]; + p3d::AsciiToUnicode(szName, string, strlen(szName)); + + p->SetString(string); + p->SetColour(colour); + p->SetScale(20.0f); //Fudge factor to make font appear about 1 meter high + _pText[_NumText]._Pos = pos; + _NumText++; + } +} + +void Section::AddScreenLine(const rmt::Vector &a, const rmt::Vector &b, tColour colour) +{ + if(_NumScreenLines < MaxScreenLines) + { + _ScreenLines[_NumScreenLines]._a = a; + _ScreenLines[_NumScreenLines]._b = b; + _ScreenLines[_NumScreenLines]._Colour = colour; + _NumScreenLines++; + } +} + +void Section::AddScreenText(const char* szName, tColour colour ) +{ + assert(szName); + ScreenText &pST = _pScreenText[_NumScreenText]; + + if(_NumScreenText<MaxScreenText && pST._pText) + { + strncpy(pST._pText, szName, sizeof(pST._pText)); + pST._Colour = colour; + pST._Pos = rmt::Vector(0.05f,_ScreenTextPos, 0); + + //TODO:get correct debug font height! + _ScreenTextPos += 0.03f; + _NumScreenText++; + } +} +void Section::AddScreenText(const char* szName, const rmt::Vector &a, tColour colour) +{ + assert(szName); + ScreenText &pST = _pScreenText[_NumScreenText]; + + if(_NumScreenText<MaxScreenText && pST._pText) + { + if(pST._pText) + strncpy(pST._pText, szName, sizeof(pST._pText)); + pST._Colour = colour; + pST._Pos = a; + _NumScreenText++; + } +} + +void Section::ClearScreenText() +{ + _NumScreenText = 0; + _ScreenTextPos = 0.15f; +} + +void Section::Render() +{ + pddiPrimStream* pStream; + int i; + assert(_pLineShader); + + //Special case to get the pddi debugging information + p3d::pddi->EnableStatsOverlay(0==strcmp(_szName, "pddi")); + + //Stream out world space lines + if(_NumLines > 0) + { + pStream = p3d::pddi->BeginPrims(_pLineShader, PDDI_PRIM_LINES, PDDI_V_C, _NumLines*2); + if(pStream) + { + for(i=0; i<_NumLines; i++) + { + Line &l = _Lines[i]; + + pddiVector A(l._a.x, l._a.y, l._a.z); + pddiVector B(l._b.x, l._b.y, l._b.z); + pStream->Vertex(&A,l._Colour); + pStream->Vertex(&B,l._Colour); + } + } + p3d::pddi->EndPrims(pStream); + } + + //Draw all the world space vector text + for(i=0;i<_NumText;i++) + { + p3d::stack->Push(); + p3d::stack->Translate(_pText[i]._Pos); + _pText[i]._pText->Display(); + p3d::stack->Pop(); + } + + //Draw screen space lines + { + //Setup the matrix stack + p3d::stack->Push(); + p3d::pddi->EnableZBuffer(false); + p3d::stack->LoadIdentity(); + p3d::stack->Scale((float)p3d::display->GetWidth(),(float)p3d::display->GetHeight(),1); + p3d::pddi->SetProjectionMode(PDDI_PROJECTION_DEVICE); + + //Stream out lines + if(_NumScreenLines > 0) + { + pStream = p3d::pddi->BeginPrims(_pLineShader, PDDI_PRIM_LINES, PDDI_V_C, _NumScreenLines*2); + if(pStream) + { + for(i=0; i<_NumScreenLines; i++) + { + Line &l = _ScreenLines[i]; + + pddiVector A(l._a.x, l._a.y, 1); + pddiVector B(l._b.x, l._b.y, 1); + pStream->Vertex(&A,l._Colour); + pStream->Vertex(&B,l._Colour); + } + } + p3d::pddi->EndPrims(pStream); + } + + //Restore the old stack + p3d::pddi->SetProjectionMode(PDDI_PROJECTION_PERSPECTIVE); + p3d::pddi->EnableZBuffer(true); + p3d::stack->Pop(); + } + + //Draw all the screen text + p3d::stack->Push(); + p3d::stack->LoadIdentity(); + int height = p3d::display->GetHeight(); + int width = p3d::display->GetWidth(); + + for(i=0;i<_NumScreenText;i++) + { + ScreenText &pST = _pScreenText[i]; + if(pST._pText) + { + + p3d::pddi->DrawString(pST._pText, + (int)(pST._Pos.x*width), + (int)(pST._Pos.y*height), + pST._Colour); + + } + } + + p3d::stack->Pop(); +} + diff --git a/game/code/debug/section.h b/game/code/debug/section.h new file mode 100644 index 0000000..85547ba --- /dev/null +++ b/game/code/debug/section.h @@ -0,0 +1,108 @@ + + +#if 1 + +#ifndef _SECTION_HPP +#define _SECTION_HPP + +#include <p3d/textstring.hpp> +#include <p3d/font.hpp> +#include <pddi/pddi.hpp> +#include <radmath/radmath.hpp> + +// TODO: move this to internal namespace + +/** + * Section. + */ +class Section +{ +public: + /** Constructor + * @param sectionName name of the section + */ + Section(tFont* pFont, const char* sectionName); + + /** Destructor */ + ~Section(); + + void SetAutoReset(bool autoReset) { _autoReset = autoReset; } + bool GetAutoReset() { return _autoReset; } + + void Reset(const char *name); + void ClearScreenText(); + void Render(); + + const char* GetName() const; + + //Debugging output functions + void AddLine(const rmt::Vector &a, const rmt::Vector &b, tColour colour); + void AddText(const char *szName, const rmt::Vector &pos, tColour colour); + + //Output functions for screen space primitives + //All screen space is in x=[0..1], y=[0..1], with (0,0) at the top left + void AddScreenLine(const rmt::Vector &a, const rmt::Vector &b, tColour colour); + void AddScreenText(const char* szName, tColour colour); + void AddScreenText(const char* szName, const rmt::Vector &a, tColour colour); + +private: + struct Line + { + rmt::Vector _a; + rmt::Vector _b; + tColour _Colour; + }; + + struct ScreenText + { + enum { MaxTextSize = 256 }; + + tColour _Colour; + char _pText[MaxTextSize]; + rmt::Vector _Pos; + }; + + struct VectorText + { + tTextString* _pText; + rmt::Vector _Pos; + }; + + +private: + char _szName[256]; + + tFont* _pDebugFont; + + float _ScreenTextPos; + + pddiShader* _pLineShader; + + int _NumLines; + enum { MaxLines = 50 }; + Line _Lines[MaxLines]; + + int _NumScreenLines; + enum { MaxScreenLines = 50 }; + Line _ScreenLines[MaxScreenLines]; + + int _NumText; + enum { MaxText = 50 }; + VectorText _pText[MaxText]; + + int _NumScreenText; + enum { MaxScreenText = 50 }; + ScreenText _pScreenText[MaxScreenText]; + + bool _autoReset; + +//denied +private: + Section();//don't use default constructor +}; + + +#endif + + +#endif |