Performance measurement hotkey added. Press ctrl+k in debug mode to grab a sample.

On level exit, it writes a .csv file with your samples. Also, for each sample it
writes a screenshot with a custom filename, so you can match up the sample with a
picture of what you sampled. For analysing where we have graphics performance problems.
master
per 2013-10-05 12:06:27 +02:00
parent 6f1666fde0
commit 5f32c3eafe
8 changed files with 162 additions and 11 deletions

View File

@ -96,6 +96,7 @@ void pie_ScreenFlip(int clearMode)
screenDoDumpToDiskIfRequired();
wzScreenFlip();
wzPerfFrame();
if (clearMode & CLEAR_OFF_AND_NO_BUFFER_DOWNLOAD)
{
return;

View File

@ -24,6 +24,7 @@
*
*/
#include <QFile>
#include "lib/framework/frame.h"
#include "lib/framework/opengl.h"
@ -55,6 +56,12 @@ static bool screendump_required = false;
static GFX *backdropGfx = NULL;
static bool perfStarted = false;
static GLuint perfpos[PERF_COUNT];
struct PERF_STORE { GLuint64 counters[PERF_COUNT]; };
static QList<PERF_STORE> perfList;
static PERF_POINT queryActive = PERF_COUNT;
static int preview_width = 0, preview_height = 0;
static Vector2i player_pos[MAX_PLAYERS];
static bool mappreview = false;
@ -139,6 +146,7 @@ bool screenInitialise()
debug(LOG_3D, " * texture cube_map %s supported.", GLEW_ARB_texture_cube_map ? "is" : "is NOT");
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &glMaxTUs);
debug(LOG_3D, " * Total number of Texture Units (TUs) supported is %d.", (int) glMaxTUs);
debug(LOG_3D, " * GL_ARB_timer_query %s supported!", GLEW_ARB_timer_query ? "is" : "is NOT");
screenWidth = MAX(screenWidth, 640);
screenHeight = MAX(screenHeight, 480);
@ -186,10 +194,112 @@ bool screenInitialise()
// Generate backdrop render
backdropGfx = new GFX(GFX_TEXTURE, GL_TRIANGLE_STRIP, 2);
if (GLEW_ARB_timer_query)
{
glGenQueries(PERF_COUNT, perfpos);
}
glErrors();
return true;
}
bool wzPerfAvailable()
{
return GLEW_ARB_timer_query;
}
void wzPerfStart()
{
if (GLEW_ARB_timer_query)
{
char text[80];
ssprintf(text, "Starting performance sample %02d", perfList.size());
GL_DEBUG(text);
perfStarted = true;
}
}
void wzPerfShutdown()
{
if (perfList.size() == 0)
{
return;
}
// write performance counter list to file
QFile perf("gfx-performance.csv");
perf.open(QIODevice::WriteOnly);
perf.write("START, EFF, TERRAIN, LOAD, PRTCL, WATER, MODELS, MISC\n");
for (int i = 0; i < perfList.size(); i++)
{
QString line;
line += QString::number(perfList[i].counters[PERF_START_FRAME]);
for (int j = 1; j < PERF_COUNT; j++)
{
line += ", " + QString::number(perfList[i].counters[j]);
}
line += "\n";
perf.write(line.toUtf8());
}
// all done, clear data
perfStarted = false;
perfList.clear();
queryActive = PERF_COUNT;
}
// call after swap buffers
void wzPerfFrame()
{
if (!perfStarted)
{
return; // not started yet
}
ASSERT(queryActive == PERF_COUNT, "Missing wfPerfEnd() call");
PERF_STORE store;
for (int i = 0; i < PERF_COUNT; i++)
{
glGetQueryObjectui64v(perfpos[i], GL_QUERY_RESULT, &store.counters[i]);
}
glErrors();
perfList.append(store);
perfStarted = false;
// Make a screenshot to document sample content
time_t aclock;
struct tm *t;
time(&aclock); /* Get time in seconds */
t = localtime(&aclock); /* Convert time to struct */
ssprintf(screendump_filename, "screenshots/wz2100-perf-sample-%02d-%04d%02d%02d_%02d%02d%02d-%s.png", perfList.size() - 1,
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, getLevelName());
screendump_required = true;
GL_DEBUG("Performance sample complete");
}
void wzPerfBegin(PERF_POINT pp, const char *descr)
{
GL_DEBUG(descr);
if (!perfStarted)
{
return;
}
ASSERT(queryActive == PERF_COUNT || pp > queryActive, "Out of order timer query call");
glBeginQuery(GL_TIME_ELAPSED, perfpos[pp]);
queryActive = pp;
glErrors();
}
void wzPerfEnd(PERF_POINT pp)
{
if (!perfStarted)
{
return;
}
ASSERT(queryActive == pp, "Mismatched wzPerfBegin...End");
glEndQuery(GL_TIME_ELAPSED);
queryActive = PERF_COUNT;
}
void screenShutDown(void)
{
pie_Skybox_Shutdown();
@ -198,6 +308,7 @@ void screenShutDown(void)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glErrors();
}
// Make OpenGL's VBO functions available under the core names for drivers that support OpenGL 1.4 only but have the VBO extension

View File

@ -63,6 +63,28 @@ void screen_enableMapPreview(int width, int height, Vector2i *playerpositions);
void screen_disableMapPreview(void);
void screen_EnableMissingFunctions();
/// gaphics performance measurement points
enum PERF_POINT
{
PERF_START_FRAME,
PERF_EFFECTS,
PERF_TERRAIN,
PERF_MODEL_INIT,
PERF_PARTICLES,
PERF_WATER,
PERF_MODELS,
PERF_MISC,
PERF_COUNT
};
void wzPerfBegin(PERF_POINT pp, const char *descr);
void wzPerfEnd(PERF_POINT pp);
void wzPerfStart();
void wzPerfShutdown();
void wzPerfFrame();
/// Are performance measurements available?
bool wzPerfAvailable();
struct OPENGL_DATA
{
char vendor[256];

View File

@ -38,6 +38,7 @@
#include "lib/ivis_opengl/piemode.h"
#include "lib/framework/fixedpoint.h"
#include "lib/ivis_opengl/piefunc.h"
#include "lib/ivis_opengl/screen.h"
#include "lib/gamelib/gtime.h"
#include "lib/gamelib/animobj.h"
@ -677,7 +678,7 @@ static void setupConnectionStatusForm(void)
/// Render the 3D world
void draw3DScene( void )
{
GL_DEBUG("Draw 3D scene - start");
wzPerfBegin(PERF_START_FRAME, "Start 3D scene");
/* What frame number are we on? */
currentGameFrame = frameGetFrameNumber();
@ -704,10 +705,12 @@ void draw3DScene( void )
pie_Begin3DScene();
/* Set 3D world origins */
pie_SetGeometricOffset(rendSurface.width / 2, geoOffset);
wzPerfEnd(PERF_START_FRAME);
// draw terrain
displayTerrain();
wzPerfBegin(PERF_MISC, "3D scene - misc text");
pie_BeginInterface();
drawDroidSelections();
@ -726,7 +729,6 @@ void draw3DScene( void )
pie_SetFogStatus(true);
}
GL_DEBUG("Draw 3D scene - text");
if (!bRender3DOnly)
{
/* Ensure that any text messages are displayed at bottom of screen */
@ -856,6 +858,7 @@ void draw3DScene( void )
showDroidPaths();
}
wzPerfEnd(PERF_MISC);
GL_DEBUG("Draw 3D scene - end");
}
@ -1017,12 +1020,14 @@ static void drawTiles(iView *player)
}
/* This is done here as effects can light the terrain - pause mode problems though */
wzPerfBegin(PERF_EFFECTS, "3D scene - effects");
processEffects();
atmosUpdateSystem();
avUpdateTiles();
wzPerfEnd(PERF_EFFECTS);
// now we are about to draw the terrain
GL_DEBUG("Draw 3D scene - terrain");
wzPerfBegin(PERF_TERRAIN, "3D scene - terrain");
pie_SetFogStatus(true);
pie_MatBegin();
@ -1034,12 +1039,13 @@ static void drawTiles(iView *player)
// and to the warzone modelview transform
pie_MatEnd();
wzPerfEnd(PERF_TERRAIN);
// draw skybox
renderSurroundings();
// and prepare for rendering the models
GL_DEBUG("Draw 3D scene - models");
wzPerfBegin(PERF_MODEL_INIT, "Draw 3D scene - model init");
pie_SetRendMode(REND_OPAQUE);
/* ---------------------------------------------------------------- */
@ -1056,10 +1062,13 @@ static void drawTiles(iView *player)
displayDelivPoints();
display3DProjectiles(); // may be bucket render implemented
pie_MatEnd();
wzPerfEnd(PERF_MODEL_INIT);
GL_DEBUG("Draw 3D scene - particles");
wzPerfBegin(PERF_PARTICLES, "3D scene - particles");
atmosDrawParticles();
wzPerfEnd(PERF_PARTICLES);
wzPerfBegin(PERF_WATER, "3D scene - water");
// prepare for the water and the lightmap
pie_SetFogStatus(true);
@ -1071,11 +1080,12 @@ static void drawTiles(iView *player)
// and to the warzone modelview transform
pie_MatEnd();
wzPerfEnd(PERF_WATER);
GL_DEBUG("Draw 3D scene - bucket render");
wzPerfBegin(PERF_MODELS, "3D scene - models");
bucketRenderCurrentList();
GL_DEBUG("Draw 3D scene - blue prints");
GL_DEBUG("Draw 3D scene - blueprints");
displayBlueprints();
pie_RemainingPasses(); // draws shadows and transparent shapes
@ -1088,8 +1098,7 @@ static void drawTiles(iView *player)
/* Clear the matrix stack */
pie_MatEnd();
locateMouse();
GL_DEBUG("Draw 3D scene - end of tiles");
wzPerfEnd(PERF_MODELS);
}
/// Initialise the fog, skybox and some other stuff

View File

@ -931,6 +931,7 @@ bool stageOneShutDown(void)
debug(LOG_WZ, "== stageOneShutDown ==");
atmosSetWeatherType(WT_NONE); // reset weather and free its data
wzPerfShutdown();
pie_FreeShaders();

View File

@ -182,6 +182,11 @@ void kf_ToggleShowPath(void)
showPath = !showPath;
}
void kf_PerformanceSample()
{
wzPerfStart();
}
// --------------------------------------------------------------------------
void kf_ToggleRadarJump( void )
{

View File

@ -262,4 +262,6 @@ void kf_BuildPrevPage( void );
extern void kf_DamageMe(void);
extern void kf_AutoGame(void);
void kf_PerformanceSample();
#endif // __INCLUDED_SRC_KEYBIND_H__

View File

@ -252,7 +252,7 @@ _keymapsave keyMapSaveTable[] =
kf_ToggleDrivingMode,
kf_ToggleShowGateways,
kf_ToggleShowPath,
kf_MapCheck,
kf_PerformanceSample,
kf_SetDroidGoToTransport,
kf_NOOP,
kf_toggleTrapCursor,
@ -469,7 +469,7 @@ void keyInitMappings( bool bForceDefaults )
keyAddMapping(KEYMAP__DEBUG, KEY_LCTRL, KEY_J, KEYMAP_PRESSED, kf_ToggleFog, N_("Toggles All fog"));
keyAddMapping(KEYMAP__DEBUG, KEY_LCTRL, KEY_Q, KEYMAP_PRESSED, kf_ToggleWeather, N_("Trigger some weather"));
keyAddMapping(KEYMAP__DEBUG, KEY_IGNORE, KEY_K, KEYMAP_PRESSED, kf_TriFlip, N_("Flip terrain triangle"));
keyAddMapping(KEYMAP__DEBUG, KEY_LCTRL, KEY_K, KEYMAP_PRESSED, kf_MapCheck, N_("Realign height of all objects on the map"));
keyAddMapping(KEYMAP__DEBUG, KEY_LCTRL, KEY_K, KEYMAP_PRESSED, kf_PerformanceSample, N_("Make a performance measurement sample"));
//These ones are necessary for debugging
keyAddMapping(KEYMAP__DEBUG, KEY_LALT, KEY_A, KEYMAP_PRESSED, kf_AllAvailable, N_("Make all items available"));