ogl_tex: centralize OpenGL caps detection; allow user override for broken card/driver combos

- enable floating point exceptions (helps catch bugs)
file.cpp: improved error checking in dir_open/dir_next_ent code
vfs.h: expand docs; add note on patching + SCM
main: use spf (1/fps) to derive TimeSinceLastFrame (makes for smoother
updates)
timer: rename SUM_TIMER to TIMER_ACCRUE. interface change allows
unlimited number of timers (instead of static limit as before).
documented everything

This was SVN commit r2958.
This commit is contained in:
janwas 2005-10-17 23:35:16 +00:00
parent f2b662d12d
commit b350f54162
15 changed files with 294 additions and 140 deletions

View File

@ -84,7 +84,7 @@ TIMER_ADD_CLIENT(tc_mipmap_basecolor);
// in m_BaseColor member
void CTextureEntry::BuildBaseColor()
{
SUM_TIMER(tc_mipmap_basecolor);
TIMER_ACCRUE(tc_mipmap_basecolor);
if (m_pProperties && m_pProperties->HasBaseColor())
{

View File

@ -157,7 +157,10 @@ void cpu_init()
// we need full precision when calculating the time.
// if there's a spot where we want to speed up divides|sqrts,
// we can temporarily change precision there.
// _control87(_PC_24, _MCW_PC);
//_control87(_PC_24, _MCW_PC);
// enable all floating-point exceptions (helps catch bugs)
_control87(_MCW_EM, _MCW_EM);
// detects CPU clock frequency and capabilities, which are prerequisites
// for using the TSC as a timer (desirable due to its high resolution).

View File

@ -347,19 +347,24 @@ int dir_open(const char* P_path, DirIterator* d_)
d->os_dir = opendir(n_path);
if(!d->os_dir)
{
int err = -1;
int err;
switch(errno)
{
case ENOMEM:
err = ERR_NO_MEM;
break;
case ENOENT:
err = ERR_PATH_NOT_FOUND;
// default: err already set
break;
default:
err = -1;
break;
}
CHECK_ERR(err);
}
return pp_set_dir(&d->pp, n_path);
RETURN_ERR(pp_set_dir(&d->pp, n_path));
return 0;
}
@ -371,9 +376,14 @@ int dir_next_ent(DirIterator* d_, DirEnt* ent)
DirIterator_* d = (DirIterator_*)d_;
get_another_entry:
errno = 0;
struct dirent* os_ent = readdir(d->os_dir);
if(!os_ent)
{
if(errno)
debug_warn("readdir failed");
return ERR_DIR_END;
}
// copy os_ent.name[]; we need it for stat() #if !OS_WIN and
// return it as ent.name (since os_ent.name[] is volatile).

View File

@ -105,19 +105,24 @@ modder (since all files would first have to be copied somewhere).
Allowing overriding individual files is much safer (since game data is
never touched) and easier (more fine-grained control for modders).
Alternatives to the patch archive approach would be to completely replace
the game data archive (infeasible due to size) or apply a binary patch
(complicated and brittle WRT versioning). We are therefore happy to
use the already existing mod mechanism.
Patching
--------
As mentioned above, patching is also done via mounting.
Alternatives would be to completely replace the game data archive
(infeasible due to size) or apply a binary patch (complicated and
brittle WRT versioning). We are therefore happy to use the
already existing mod mechanism.
Note however that multiple patches do impact performance (despite
constant-time VFS path -> file location lookup) simply due to locality;
files are no longer arranged in order of access. Fortunately there is an
easy way to avoid this: simply run the archive builder script; all
patched files will be merged into the archive.
For more information, see 'Mount Details' below.
patched files will be merged into the archive. However, be warned that
reverting to previous versions (e.g. to watch old replays) would no longer
be possible! This is because their changes have been 'baked into' the
main archive, whereas previously the patch could simply be deleted.
Mount Details
@ -176,6 +181,8 @@ this is just an optimization.
To ease development, files may additionally be stored in normal directories.
The VFS transparently provides access to the correct (newest) version.
This is to allow keeping data files in SCM - developers can get the latest
version without always having to update archives afterwards.
One additional advantage of archives over loose files is that I/O throughput
is increased - since files are compressed, there is less to read from disk.

View File

@ -674,7 +674,7 @@ static int ZArchive_validate(const ZArchive* za)
// somewhat slow - each file is added to an internal index.
Handle zip_archive_open(const char* fn)
{
TIMER(zip_archive_open);
TIMER("zip_archive_open");
return h_alloc(H_ZArchive, fn);
}
@ -816,12 +816,12 @@ double t0 = get_time();
if(ctx->compressed)
{
SUM_TIMER(tc_zip_inflate);
TIMER_ACCRUE(tc_zip_inflate);
err = inflate(zs, Z_SYNC_FLUSH);
}
else
{
SUM_TIMER(tc_zip_memcpy);
TIMER_ACCRUE(tc_zip_memcpy);
memcpy2(zs->next_out, zs->next_in, zs->avail_in);
uInt size = MIN(zs->avail_in, zs->avail_out);
zs->avail_out -= size;

View File

@ -506,6 +506,7 @@ int ogl_tex_free(Handle& ht)
//----------------------------------------------------------------------------
// state setters (see "Texture Parameters" in docs)
//----------------------------------------------------------------------------
// we require the below functions be called before uploading; this avoids
// potentially redundant glTexParameter calls (we'd otherwise need to always
@ -587,12 +588,84 @@ int ogl_tex_set_wrap(Handle ht, GLint wrap)
//----------------------------------------------------------------------------
// upload
//----------------------------------------------------------------------------
// OpenGL has several features that are helpful for uploading but not
// available in all implementations. we check for their presence but
// provide for user override (in case they don't work on a card/driver
// combo we didn't test).
// tristate; -1 is undecided
static int have_auto_mipmap_gen = -1;
static int have_s3tc = -1;
// override the default decision and force/disallow use of the
// given feature. should be called from ah_override_gl_upload_caps.
void ogl_tex_override(OglTexOverrides what, OglTexAllow allow)
{
debug_assert(allow == OGL_TEX_ENABLE || allow == OGL_TEX_DISABLE);
const bool enable = (allow == OGL_TEX_ENABLE);
switch(what)
{
case OGL_TEX_S3TC:
have_s3tc = enable;
break;
case OGL_TEX_AUTO_MIPMAP_GEN:
have_auto_mipmap_gen = enable;
break;
default:
debug_warn("ogl_tex_override: invalid <what>");
break;
}
}
// detect caps (via OpenGL extension list) and give an app_hook the chance to
// override this (e.g. via list of card/driver combos on which S3TC breaks).
// called once from the first ogl_tex_upload.
static void detect_gl_upload_caps()
{
// detect features, but only change the variables if they were at
// "undecided" (if overrides were set before this, they must remain).
if(have_auto_mipmap_gen == -1)
{
have_auto_mipmap_gen = oglHaveExtension("GL_SGIS_generate_mipmap");
}
if(have_s3tc == -1)
{
// note: we don't bother checking for GL_S3_s3tc - it is incompatible
// and irrelevant (was never widespread).
have_s3tc = oglHaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", 0) == 0;
}
//apphook - call back into override if app thinks anything should be disabled
// disable features if we're on a card/driver combo on which they
// are known to break.
if(gfx_card[0] == '\0')
debug_warn("ogl_tex requires get_gfx_info be called before ogl_tex_upload");
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
{
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
have_s3tc = false;
}
// warn if more-or-less essential features are missing
if(!have_s3tc)
DISPLAY_ERROR(L"Performance warning: your graphics card does not support compressed textures. The game will try to continue anyway, but may be slower than expected. Please try updating your graphics drivers; if that doesn't help, please try upgrading your hardware.");
}
// take care of mipmaps. if they are called for by <filter>, either
// arrange for OpenGL to create them, or see to it that the Tex object
// contains them (if need be, creating them in software).
// sets *plevels_to_skip to influence upload behavior (depending on
// whether mipmaps are needed and the quality settings).
// returns 0 to indicate success; otherwise, caller must disable
// mipmapping by switching filter to e.g. GL_LINEAR.
static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
{
// decisions:
// .. does this OpenGL implementation support auto mipmap generation?
static const bool have_auto_mipmap_gen = oglHaveVersion("1.4") || oglHaveExtension("GL_SGIS_generate_mipmap");
// .. does filter call for uploading mipmaps?
const bool need_mipmaps = filter_uses_mipmaps(filter);
// .. does the image data include mipmaps? (stored as separate
@ -652,6 +725,8 @@ static int get_mipmaps(Tex* t, GLint filter, uint q_flags, int* plevels_to_skip)
}
// tex_util_foreach_mipmap callbacks: upload the given level to OpenGL.
struct UploadParams
{
GLenum fmt;
@ -693,26 +768,6 @@ static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip)
}
static bool detect_s3tc()
{
// 1. require extensions to be advertised.
// note: we don't bother checking for GL_S3_s3tc - it is incompatible
// and irrelevant (was never widespread).
bool have_s3tc = oglHaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", 0) == 0;
// 2. exclude any card/driver combos on which it is known to break.
if(gfx_card[0] == '\0')
debug_warn("ogl_tex requires get_gfx_info be called before ogl_tex_upload");
if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014"))
{
if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)"))
have_s3tc = false;
}
return have_s3tc;
}
// upload the texture to OpenGL.
// if not 0, parameters override the following:
// fmt_ovr : OpenGL format (e.g. GL_RGB) decided from bpp / Tex flags;
@ -724,6 +779,8 @@ static bool detect_s3tc()
// - frees the texel data! see ogl_tex_get_data.
int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_fmt_ovr)
{
ONCE(detect_gl_upload_caps());
H_DEREF(ht, OglTex, ot);
Tex* t = &ot->t;
const char* fn = h_filename(ht);
@ -738,12 +795,8 @@ int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_
return 0;
// decompress S3TC if that's not supported by OpenGL.
static const bool have_s3tc = detect_s3tc();
if((t->flags & TEX_DXT) && !have_s3tc)
{
ONCE(DISPLAY_ERROR(L"Performance warning: your graphics card does not support compressed textures. The game will try to continue anyway, but may be slower than expected. Please try updating your graphics drivers; if that doesn't help, please try upgrading your hardware."));
(void)tex_transform_to(t, t->flags & ~TEX_DXT);
}
// determine fmt and int_fmt, allowing for user override.
ot->fmt = choose_fmt(t->bpp, t->flags);
@ -788,6 +841,7 @@ int ogl_tex_upload(const Handle ht, GLenum fmt_ovr, uint q_flags_ovr, GLint int_
//----------------------------------------------------------------------------
// getters
//----------------------------------------------------------------------------
// retrieve texture dimensions and bits per pixel.
// all params are optional and filled if non-NULL.
@ -842,6 +896,7 @@ int ogl_tex_get_data(Handle ht, void** p)
//----------------------------------------------------------------------------
// misc API
//----------------------------------------------------------------------------
// bind the texture to the specified unit [number] in preparation for
// using it in rendering. if <ht> is 0, texturing is disabled instead.

View File

@ -237,6 +237,20 @@ extern int ogl_tex_set_wrap(Handle ht, GLint wrap);
// upload
//
enum OglTexOverrides
{
OGL_TEX_S3TC,
OGL_TEX_AUTO_MIPMAP_GEN
};
enum OglTexAllow
{
OGL_TEX_DISABLE,
OGL_TEX_ENABLE
};
extern void ogl_tex_override(OglTexOverrides what, OglTexAllow allow);
// upload the texture to OpenGL.
// if not 0, parameters override the following:
// fmt_ovr : OpenGL format (e.g. GL_RGB) decided from bpp / Tex flags;

View File

@ -660,7 +660,7 @@ TIMER_ADD_CLIENT(tc_transform);
// that are set in transforms.
int tex_transform(Tex* t, uint transforms)
{
SUM_TIMER(tc_transform);
TIMER_ACCRUE(tc_transform);
const uint target_flags = t->flags ^ transforms;
for(;;)

View File

@ -40,10 +40,13 @@ extern u64 rdtsc(void);
#ifndef _MCW_PC
#define _MCW_PC 0x0300 // Precision Control
# define _MCW_PC 0x0300 // Precision Control
#endif
#ifndef _PC_24
#define _PC_24 0x0000 // 24 bits
# define _PC_24 0x0000 // 24 bits
#endif
#ifndef _MCW_EM
# define _MCW_EM 0x003f // Exception Mask
#endif
#define _control87 ia32_control87

View File

@ -37,7 +37,6 @@ double get_time()
double t;
#if HAVE_CLOCK_GETTIME
static struct timespec start = {0};
struct timespec ts;
@ -46,9 +45,7 @@ double get_time()
(void)clock_gettime(CLOCK_REALTIME, &ts);
t = (ts.tv_sec - start.tv_sec) + (ts.tv_nsec - start.tv_nsec)*1e-9;
#elif HAVE_GETTIMEOFDAY
static struct timeval start;
struct timeval cur;
@ -57,11 +54,8 @@ double get_time()
gettimeofday(&cur, 0);
t = (cur.tv_sec - start.tv_sec) + (cur.tv_usec - start.tv_usec)*1e-6;
#else
#error "get_time: add timer implementation for this platform!"
#endif
// make sure time is monotonic (never goes backwards)
@ -74,6 +68,8 @@ double get_time()
}
// return resolution (expressed in [s]) of the time source underlying
// get_time.
double timer_res()
{
// may take a while to determine, so cache it
@ -110,6 +106,7 @@ double timer_res()
// filter values are tuned for 100 FPS.
int fps;
float spf;
void calc_fps()
{
@ -225,6 +222,8 @@ void calc_fps()
old = cur_fps*gain + old*(1.0-gain);
avg_fps = old;
spf = 1.0 / avg_fps;
// update fps counter if it differs "enough"
// currently, that means off by more than 5 FPS or 5%.
const double difference = fabs(avg_fps-fps);
@ -242,15 +241,20 @@ void calc_fps()
// this supplements in-game profiling by providing low-overhead,
// high resolution time accounting.
// use static storage to ensure clients can be added at any time,
// especially before the heap has been initialized.
// intrusive linked-list of all clients. a fixed-size limit would be
// acceptable (since timers are added manually), but the list is easy
// to implement and only has the drawback of exposing TimerClient to users.
//
// do not use std::list et al. for this! we must be callable at any time,
// especially before NLSO ctors run or before heap init.
static uint num_clients;
static TimerClient* clients;
// allocate a new TimerClient whose total (added to by timer_bill_client)
// will be displayed by timer_display_client_totals.
// make the given TimerClient (usually instantiated as static data)
// ready for use. returns its address for TIMER_ADD_CLIENT's convenience.
// this client's total (added to by timer_bill_client) will be
// displayed by timer_display_client_totals.
// notes:
// - may be called at any time;
// - always succeeds (there's no fixed limit);

View File

@ -30,13 +30,16 @@ extern "C" {
// high resolution (> 1 us) timestamp [s], starting at or near 0 s.
extern double get_time(void);
// return resolution (expressed in [s]) of the time source underlying
// get_time.
extern double timer_res(void);
// calculate fps (call once per frame)
// several smooth filters (tuned for ~100 FPS)
// => less fluctuation, but rapid tracking
extern int fps;
extern int fps; // for user display
extern float spf; // for time-since-last-frame use
extern void calc_fps(void);
@ -45,7 +48,10 @@ extern void calc_fps(void);
// cumulative timer API
//
// this is to be considered opaque - do not access its fields!
// this supplements in-game profiling by providing low-overhead,
// high resolution time accounting.
// opaque - do not access its fields!
// note: must be defined here because clients instantiate them;
// fields cannot be made private due to C compatibility requirement.
struct TimerClient
@ -56,13 +62,13 @@ struct TimerClient
const char* description;
TimerClient* next;
int dummy;
};
// allocate a new TimerClient whose total (added to by timer_bill_client)
// will be displayed by timer_display_client_totals.
// make the given TimerClient (usually instantiated as static data)
// ready for use. returns its address for TIMER_ADD_CLIENT's convenience.
// this client's total (added to by timer_bill_client) will be
// displayed by timer_display_client_totals.
// notes:
// - may be called at any time;
// - always succeeds (there's no fixed limit);
@ -70,10 +76,6 @@ struct TimerClient
// - description must remain valid until exit; a string literal is safest.
extern TimerClient* timer_add_client(TimerClient* tc, const char* description);
#define TIMER_ADD_CLIENT(id)\
static TimerClient UID__;\
TimerClient* id = timer_add_client(&UID__, #id);
// add <dt> [s] to the client's total.
extern void timer_bill_client(TimerClient* tc, double dt);
@ -87,18 +89,21 @@ extern void timer_display_client_totals();
class ScopedTimer
// used via TIMER* macros below.
class ScopeTimer
{
double t0;
const char* name;
const char* description;
public:
ScopedTimer(const char* _name)
ScopeTimer(const char* _description)
{
t0 = get_time();
name = _name;
description = _description;
}
~ScopedTimer()
~ScopeTimer()
{
double t1 = get_time();
double dt = t1-t0;
@ -111,50 +116,70 @@ public:
else if(dt > 1e-3)
scale = 1e3, unit = "ms";
debug_printf("TIMER %s: %g %s\n", name, dt*scale, unit);
debug_printf("TIMER %s: %g %s\n", description, dt*scale, unit);
}
// disallow copying (makes no sense)
private:
ScopedTimer& operator=(const ScopedTimer&);
ScopeTimer& operator=(const ScopeTimer&);
};
#define TIMER(name) ScopedTimer ST##name(#name)
// Cheat a bit to make things slightly easier on the user
#define TIMER_START(name) { ScopedTimer __timer( name )
#define TIMER_END(name) }
/*
Measure the time taken to execute code up until end of the current scope;
display it via debug_printf. Can safely be nested.
Useful for measuring time spent in a function or basic block.
<description> must remain valid over the lifetime of this object;
a string literal is safest.
Example usage:
static TimerClient* client = timer_add_client("description");
void func()
{
SUM_TIMER(client);
(code to be measured)
TIMER("description");
// code to be measured
}
[at exit]
timer_display_client_totals();
*/
#define TIMER(description) ScopeTimer UID__(description)
class ScopedSumTimer
/*
Measure the time taken to execute code between BEGIN and END markers;
display it via debug_printf. Can safely be nested.
Useful for measuring several pieces of code within the same function/block.
<description> must remain valid over the lifetime of this object;
a string literal is safest.
Caveats:
- this wraps the code to be measured in a basic block, so any
variables defined there are invisible to surrounding code.
- the description passed to END isn't inspected; you are responsible for
ensuring correct nesting!
Example usage:
void func2()
{
// uninteresting code
TIMER_BEGIN("description2");
// code to be measured
TIMER_END("description2");
// uninteresting code
}
*/
#define TIMER_BEGIN(description) { ScopeTimer UID__(description)
#define TIMER_END(description) }
// used via TIMER_ACCRUE
class ScopeTimerAccrue
{
double t0;
TimerClient* tc;
public:
ScopedSumTimer(TimerClient* tc_)
ScopeTimerAccrue(TimerClient* tc_)
{
t0 = get_time();
tc = tc_;
}
~ScopedSumTimer()
~ScopeTimerAccrue()
{
double t1 = get_time();
double dt = t1-t0;
@ -163,12 +188,39 @@ public:
// disallow copying (makes no sense)
private:
ScopedSumTimer& operator=(const ScopedSumTimer&);
ScopeTimerAccrue& operator=(const ScopeTimerAccrue&);
};
// bills to <client> the time elapsed between execution reaching the
// point of macro invocation and end of the current basic block.
// total times for all clients are displayed by timer_display_client_totals.
#define SUM_TIMER(client) ScopedSumTimer UID__(client)
// "allocate" a new TimerClient that will keep track of the total time
// billed to it, along with a description string. These are displayed when
// timer_display_client_totals is called.
// Invoke this at file or function scope; a (static) TimerClient pointer of
// name <id> will be defined, which should be passed to TIMER_ACCRUE.
#define TIMER_ADD_CLIENT(id)\
static TimerClient UID__;\
static TimerClient* id = timer_add_client(&UID__, #id);
/*
Measure the time taken to execute code up until end of the current scope;
bill it to the given TimerClient object. Can safely be nested.
Useful for measuring total time spent in a function or basic block over the
entire program.
<description> must remain valid over the lifetime of this object;
a string literal is safest.
Example usage:
TIMER_ADD_CLIENT(identifier)
void func()
{
TIMER_ACCRUE(name_of_pointer_to_client);
// code to be measured
}
[at exit]
timer_display_client_totals();
*/
#define TIMER_ACCRUE(client) ScopeTimerAccrue UID__(client)
#endif // #ifndef TIMER_H

View File

@ -128,12 +128,19 @@ static void Frame()
music_player.update();
PROFILE_END( "update music" );
calc_fps();
// old method - "exact" but contains jumps
#if 0
static double last_time;
const double time = get_time();
const float TimeSinceLastFrame = (float)(time-last_time);
last_time = time;
ONCE(return);
// first call: set last_time and return
ONCE(return); // first call: set last_time and return
// new method - filtered and more smooth, but errors may accumulate
#else
const float TimeSinceLastFrame = spf;
#endif
debug_assert(TimeSinceLastFrame >= 0.0f);
PROFILE_START( "reload changed files" );
@ -230,7 +237,6 @@ static void Frame()
g_Profiler.Frame();
calc_fps();
if(g_FixedFrameTiming && frameCount==100)
kill_mainloop();
}

View File

@ -170,7 +170,7 @@ void CONFIG_Init(int argc, char* argv[])
{
debug_printf("CFG_Init &argc=%p &argv=%p\n", &argc, &argv);
TIMER(CONFIG_Init);
TIMER("CONFIG_Init");
MICROLOG(L"init config");
new CConfigDB;

View File

@ -131,14 +131,14 @@ static int SetVideoMode(int w, int h, int bpp, bool fullscreen)
void GUI_Init()
{
#ifndef NO_GUI
{TIMER(ps_gui_init);
{TIMER("ps_gui_init");
g_GUI.Initialize();}
{TIMER(ps_gui_setup_xml);
{TIMER("ps_gui_setup_xml");
g_GUI.LoadXMLFile("gui/test/setup.xml");}
{TIMER(ps_gui_styles_xml);
{TIMER("ps_gui_styles_xml");
g_GUI.LoadXMLFile("gui/test/styles.xml");}
{TIMER(ps_gui_sprite1_xml);
{TIMER("ps_gui_sprite1_xml");
g_GUI.LoadXMLFile("gui/test/sprite1.xml");}
// Atlas is running, we won't need these GUI pages (for now!
@ -147,23 +147,23 @@ void GUI_Init()
// if(ATLAS_IsRunning())
// return;
{TIMER(ps_gui_1);
{TIMER("ps_gui_1");
g_GUI.LoadXMLFile("gui/test/1_init.xml");}
{TIMER(ps_gui_2);
{TIMER("ps_gui_2");
g_GUI.LoadXMLFile("gui/test/2_mainmenu.xml");}
{TIMER(ps_gui_3);
{TIMER("ps_gui_3");
g_GUI.LoadXMLFile("gui/test/3_loading.xml");}
{TIMER(ps_gui_4);
{TIMER("ps_gui_4");
g_GUI.LoadXMLFile("gui/test/4_session.xml");}
{TIMER(ps_gui_6);
{TIMER("ps_gui_6");
g_GUI.LoadXMLFile("gui/test/6_subwindows.xml");}
{TIMER(ps_gui_6_1);
{TIMER("ps_gui_6_1");
g_GUI.LoadXMLFile("gui/test/6_1_manual.xml");}
{TIMER(ps_gui_6_2);
{TIMER("ps_gui_6_2");
g_GUI.LoadXMLFile("gui/test/6_2_jukebox.xml");}
{TIMER(ps_gui_7);
{TIMER("ps_gui_7");
g_GUI.LoadXMLFile("gui/test/7_atlas.xml");}
{TIMER(ps_gui_9);
{TIMER("ps_gui_9");
g_GUI.LoadXMLFile("gui/test/9_global.xml");}
#endif
}
@ -395,7 +395,7 @@ void Render()
static void InitScripting()
{
TIMER(InitScripting);
TIMER("InitScripting");
// Create the scripting host. This needs to be done before the GUI is created.
new ScriptingHost;
@ -449,7 +449,7 @@ static void InitScripting()
static void InitVfs(const char* argv0)
{
TIMER(InitVfs);
TIMER("InitVfs");
// set root directory to "$game_dir/data". all relative file paths
// passed to file.cpp will be based from this dir.
// (we don't set current directory because other libraries may
@ -478,7 +478,7 @@ static void InitPs(bool setup_gui)
{
// console
{
TIMER(ps_console);
TIMER("ps_console");
g_Console->UpdateScreenSize(g_xres, g_yres);
@ -491,7 +491,7 @@ static void InitPs(bool setup_gui)
// language and hotkeys
{
TIMER(ps_lang_hotkeys);
TIMER("ps_lang_hotkeys");
std::string lang = "english";
CFG_GET_SYS_VAL("language", String, lang);
@ -549,7 +549,7 @@ static void ShutdownPs()
static void InitRenderer()
{
TIMER(InitRenderer);
TIMER("InitRenderer");
// create renderer
new CRenderer;
@ -695,28 +695,28 @@ void Shutdown()
if (g_Game)
EndGame();
TIMER_START("shutdown Scheduler");
TIMER_BEGIN("shutdown Scheduler");
delete &g_Scheduler;
TIMER_END("shutdown Scheduler");
TIMER_START("shutdown SessionManager");
TIMER_BEGIN("shutdown SessionManager");
delete &g_SessionManager;
TIMER_END("shutdown SessionManager");
TIMER_START("shutdown mouse stuff");
TIMER_BEGIN("shutdown mouse stuff");
delete &g_Mouseover;
delete &g_Selection;
delete &g_BuildingPlacer;
TIMER_END("shutdown mouse stuff");
TIMER_START("shutdown Pathfinder");
TIMER_BEGIN("shutdown Pathfinder");
delete &g_Pathfinder;
TIMER_END("shutdown Pathfinder");
// Managed by CWorld
// delete &g_EntityManager;
TIMER_START("shutdown game scripting stuff");
TIMER_BEGIN("shutdown game scripting stuff");
delete &g_GameAttributes;
delete &g_JSGameEvents;
@ -724,7 +724,7 @@ void Shutdown()
TIMER_END("shutdown game scripting stuff");
// destroy actor related stuff
TIMER_START("shutdown actor stuff");
TIMER_BEGIN("shutdown actor stuff");
delete &g_UnitMan;
delete &g_ObjMan;
delete &g_SkelAnimMan;
@ -734,38 +734,38 @@ void Shutdown()
TIMER_END("shutdown actor stuff");
// destroy terrain related stuff
TIMER_START("shutdown TexMan");
TIMER_BEGIN("shutdown TexMan");
delete &g_TexMan;
TIMER_END("shutdown TexMan");
// destroy renderer
TIMER_START("shutdown Renderer");
TIMER_BEGIN("shutdown Renderer");
delete &g_Renderer;
g_VBMan.Shutdown();
TIMER_END("shutdown Renderer");
TIMER_START("shutdown ScriptingHost");
TIMER_BEGIN("shutdown ScriptingHost");
delete &g_ScriptingHost;
TIMER_END("shutdown ScriptingHost");
TIMER_START("shutdown ConfigDB");
TIMER_BEGIN("shutdown ConfigDB");
delete &g_ConfigDB;
TIMER_END("shutdown ConfigDB");
// Shut down the network loop
TIMER_START("shutdown CSocketBase");
TIMER_BEGIN("shutdown CSocketBase");
CSocketBase::Shutdown();
TIMER_END("shutdown CSocketBase");
// Really shut down the i18n system. Any future calls
// to translate() will crash.
TIMER_START("shutdown I18N");
TIMER_BEGIN("shutdown I18N");
I18n::Shutdown();
TIMER_END("shutdown I18N");
// resource
// first shut down all resource owners, and then the handle manager.
TIMER_START("resource modules");
TIMER_BEGIN("resource modules");
snd_shutdown();
vfs_shutdown();
@ -778,7 +778,7 @@ void Shutdown()
mem_shutdown();
TIMER_END("resource modules");
TIMER_START("shutdown misc");
TIMER_BEGIN("shutdown misc");
file_shutdown();
timer_display_client_totals();
@ -924,7 +924,7 @@ void Init(int argc, char* argv[], bool setup_videomode, bool setup_gui)
InitRenderer();
{
TIMER(Init_entitiessection);
TIMER("Init_entitiessection");
// This needs to be done after the renderer has loaded all its actors...
new CBaseEntityCollection;
// CEntityManager is managed by CWorld
@ -934,7 +934,7 @@ void Init(int argc, char* argv[], bool setup_videomode, bool setup_gui)
}
{
TIMER(Init_miscgamesection);
TIMER("Init_miscgamesection");
new CPathfindEngine;
new CBuildingPlacer;
new CSessionManager;
@ -942,7 +942,7 @@ void Init(int argc, char* argv[], bool setup_videomode, bool setup_gui)
}
{
TIMER(Init_misc);
TIMER("Init_misc");
// Register a few Game/Network JS globals
g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes.GetScript()));
@ -959,13 +959,13 @@ void Init(int argc, char* argv[], bool setup_videomode, bool setup_gui)
#ifndef NO_GUI
{
TIMER(Init_guiload);
TIMER("Init_guiload");
g_GUI.SendEventToAll("load");
}
#endif
{
TIMER(Init_renderblank);
TIMER("Init_renderblank");
MICROLOG(L"render blank");
// render everything to a blank frame to force renderer to load everything
RenderNoCull();

View File

@ -34,7 +34,7 @@ static std::string SplitExts(const char *exts)
void WriteSystemInfo()
{
TIMER(write_sys_info);
TIMER("write_sys_info");
// get_cpu_info and get_gfx_info already called during init - see call site
get_snd_info();