diff --git a/src/d_main.c b/src/d_main.c index c0a8eacec..09aa2d340 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -411,6 +411,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { + rs_rendercalltime = I_GetTimeMicros(); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { topleft = screens[0] + viewwindowy*vid.width + viewwindowx; @@ -457,6 +458,7 @@ static void D_Display(void) if (postimgtype2) V_DoPostProcessor(1, postimgtype2, postimgparam2); } + rs_rendercalltime = I_GetTimeMicros() - rs_rendercalltime; } if (lastdraw) @@ -591,6 +593,77 @@ static void D_Display(void) snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); } + + if (cv_renderstats.value) + { + char s[50]; + int frametime = I_GetTimeMicros() - rs_prevframetime; + int divisor = 1; + rs_prevframetime = I_GetTimeMicros(); + + if (rs_rendercalltime > 10000) divisor = 1000; + + snprintf(s, sizeof s - 1, "ft %d", frametime / divisor); + V_DrawThinString(30, 10, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "rtot %d", rs_rendercalltime / divisor); + V_DrawThinString(30, 20, V_MONOSPACE | V_YELLOWMAP, s); + if (rendermode == render_opengl)// dont show unimplemented stats + { + snprintf(s, sizeof s - 1, "bsp %d", rs_bsptime / divisor); + V_DrawThinString(30, 30, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "nsrt %d", rs_nodesorttime / divisor); + V_DrawThinString(30, 40, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "ndrw %d", rs_nodedrawtime / divisor); + V_DrawThinString(30, 50, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "ssrt %d", rs_spritesorttime / divisor); + V_DrawThinString(30, 60, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "sdrw %d", rs_spritedrawtime / divisor); + V_DrawThinString(30, 70, V_MONOSPACE | V_YELLOWMAP, s); + /*snprintf(s, sizeof s - 1, "post %d", rs_posttime / divisor); + V_DrawThinString(30, 80, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "flip %d", rs_swaptime / divisor); + V_DrawThinString(30, 90, V_MONOSPACE | V_YELLOWMAP, s); + snprintf(s, sizeof s - 1, "test %d", rs_test / divisor); + V_DrawThinString(30, 100, V_MONOSPACE | V_YELLOWMAP, s);*/ + + snprintf(s, sizeof s - 1, "nbsp %d", rs_numbspcalls); + V_DrawThinString(80, 10, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "nnod %d", rs_numdrawnodes); + V_DrawThinString(80, 20, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "nspr %d", rs_numsprites); + V_DrawThinString(80, 30, V_MONOSPACE | V_BLUEMAP, s); + snprintf(s, sizeof s - 1, "npob %d", rs_numpolyobjects); + V_DrawThinString(80, 40, V_MONOSPACE | V_BLUEMAP, s); +/* + if (cv_enable_batching.value) + { + snprintf(s, sizeof s - 1, "bsrt %d", rs_batchsorttime / divisor); + V_DrawThinString(75, 55, V_MONOSPACE | V_REDMAP, s); + snprintf(s, sizeof s - 1, "bdrw %d", rs_batchdrawtime / divisor); + V_DrawThinString(75, 65, V_MONOSPACE | V_REDMAP, s); + + snprintf(s, sizeof s - 1, "npol %d", rs_numpolys); + V_DrawThinString(130, 10, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ndc %d", rs_numcalls); + V_DrawThinString(130, 20, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "nshd %d", rs_numshaders); + V_DrawThinString(130, 30, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "nvrt %d", rs_numverts); + V_DrawThinString(130, 40, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ntex %d", rs_numtextures); + V_DrawThinString(185, 10, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "npf %d", rs_numpolyflags); + V_DrawThinString(185, 20, V_MONOSPACE | V_PURPLEMAP, s); + snprintf(s, sizeof s - 1, "ncol %d", rs_numcolors); + V_DrawThinString(185, 30, V_MONOSPACE | V_PURPLEMAP, s); + }*/ + } +/* else + { + snprintf(s, sizeof s - 1, "flip %d", rs_swaptime / divisor); + V_DrawThinString(30, 30, V_MONOSPACE | V_YELLOWMAP, s); + }*/ + } I_FinishUpdate(); // page flip or blit buffer } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 6fe0d4078..ed43ec9ae 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -146,6 +146,25 @@ static float gr_fovlud; static angle_t gr_aimingangle; static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); +// render stats +int rs_prevframetime = 0; +int rs_rendercalltime = 0; +int rs_bsptime = 0; +int rs_nodetime = 0; +int rs_nodesorttime = 0; +int rs_nodedrawtime = 0; +int rs_spritesorttime = 0; +int rs_spritedrawtime = 0; + +int rs_numdrawnodes = 0; +int rs_numbspcalls = 0; +int rs_numsprites = 0; +int rs_numpolyobjects = 0; + +//int rs_posttime = 0; +//int rs_swaptime = 0; + + // ========================================================================== // Lighting // ========================================================================== @@ -3484,6 +3503,9 @@ static void HWR_Subsector(size_t num) po = (polyobj_t *)(po->link.next); } + // for render stats + rs_numpolyobjects += numpolys; + // Sort polyobjects R_SortPolyObjects(sub); @@ -3598,6 +3620,8 @@ static void HWR_RenderBSPNode(INT32 bspnum) // Decide which side the view point is on INT32 side; + + rs_numbspcalls++; // Found a subsector? if (bspnum & NF_SUBSECTOR) @@ -4772,6 +4796,8 @@ static void HWR_CreateDrawNodes(void) // If true, swap the draw order. boolean shift = false; + + rs_nodesorttime = I_GetTimeMicros(); for (i = 0; i < numplanes; i++, p++) { @@ -4790,6 +4816,8 @@ static void HWR_CreateDrawNodes(void) sortnode[p].wall = &wallinfo[i]; sortindex[p] = p; } + + rs_numdrawnodes = p; // p is the number of stuff to sort @@ -4892,6 +4920,10 @@ static void HWR_CreateDrawNodes(void) } //i++ } // loop++ + rs_nodesorttime = I_GetTimeMicros() - rs_nodesorttime; + + rs_nodedrawtime = I_GetTimeMicros(); + // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); HWD.pfnSetShader(0); @@ -4926,6 +4958,8 @@ static void HWR_CreateDrawNodes(void) sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap); } } + + rs_nodedrawtime = I_GetTimeMicros() - rs_nodedrawtime; numwalls = 0; numplanes = 0; @@ -6002,6 +6036,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value); HWD.pfnSetShader(0); + rs_numbspcalls = 0; + rs_numpolyobjects = 0; + rs_bsptime = I_GetTimeMicros(); + validcount++; HWR_RenderBSPNode((INT32)numnodes-1); @@ -6035,6 +6073,8 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } #endif + rs_bsptime = I_GetTimeMicros() - rs_bsptime; + // Check for new console commands. NetUpdate(); @@ -6045,14 +6085,22 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) #endif // Draw MD2 and sprites + rs_numsprites = gr_visspritecount; + rs_spritesorttime = I_GetTimeMicros(); HWR_SortVisSprites(); + rs_spritesorttime = I_GetTimeMicros() - rs_spritesorttime; + rs_spritedrawtime = I_GetTimeMicros(); HWR_DrawSprites(); + rs_spritedrawtime = I_GetTimeMicros() - rs_spritedrawtime; #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? HWR_DrawCoronas(); #endif + rs_numdrawnodes = 0; + rs_nodesorttime = 0; + rs_nodedrawtime = 0; if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { HWR_CreateDrawNodes(); @@ -6118,6 +6166,11 @@ consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotro consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +// render stats +// for now have it in here in the hw code +// could have it somewhere else since renderstats could also be a software rendering thing +consvar_t cv_renderstats = {"renderstats", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + static void CV_grfiltermode_OnChange(void) { if (rendermode == render_opengl) @@ -6155,6 +6208,8 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_grfiltermode); CV_RegisterVar(&cv_grcorrecttricks); CV_RegisterVar(&cv_grsolvetjoin); + + CV_RegisterVar(&cv_renderstats); #ifndef NEWCLIP CV_RegisterVar(&cv_grclipwalls); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index aedfa9cd6..8aaa335fb 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -104,4 +104,25 @@ extern float gr_viewwindowx, gr_basewindowcentery; extern fixed_t *hwbbox; extern FTransform atransform; + +// render stats console toggle +extern consvar_t cv_renderstats; +// render stats time counter variables +extern int rs_prevframetime;// time when previous frame was rendered +extern int rs_rendercalltime; +extern int rs_bsptime; +extern int rs_nodetime; +extern int rs_nodesorttime; +extern int rs_nodedrawtime; +extern int rs_spritesorttime; +extern int rs_spritedrawtime; + +//extern int rs_posttime; +//extern int rs_swaptime; + +extern int rs_numdrawnodes; +extern int rs_numbspcalls; +extern int rs_numsprites; +extern int rs_numpolyobjects; + #endif diff --git a/src/i_system.h b/src/i_system.h index b38748244..dd0b65f6d 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -46,6 +46,8 @@ UINT32 I_GetFreeMem(UINT32 *total); */ tic_t I_GetTime(void); +int I_GetTimeMicros(void);// provides microsecond counter for render stats + /** \brief The I_Sleep function \return void diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index a86af316e..9d63225cb 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2060,9 +2060,12 @@ static p_timeGetTime pfntimeGetTime = NULL; // but lower precision on Windows NT // --------- -tic_t I_GetTime(void) +DWORD TimeFunction(boolean microseconds) { - tic_t newtics = 0; + DWORD newtics = 0; + int multiplier = 1; + + if (microseconds) multiplier = 1000; if (!starttickcount) // high precision timer { @@ -2082,7 +2085,7 @@ tic_t I_GetTime(void) if (frequency.LowPart && QueryPerformanceCounter(&currtime)) { - newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * NEWTICRATE + newtics = (INT32)((currtime.QuadPart - basetime.QuadPart) * 1000 * multiplier / frequency.QuadPart); } else if (pfntimeGetTime) @@ -2090,11 +2093,11 @@ tic_t I_GetTime(void) currtime.LowPart = pfntimeGetTime(); if (!basetime.LowPart) basetime.LowPart = currtime.LowPart; - newtics = ((currtime.LowPart - basetime.LowPart)/(1000/NEWTICRATE)); + newtics = currtime.LowPart - basetime.LowPart; } } else - newtics = (GetTickCount() - starttickcount)/(1000/NEWTICRATE); + newtics = (GetTickCount() - starttickcount) * multiplier; return newtics; } @@ -2116,6 +2119,7 @@ static void I_ShutdownTimer(void) // I_GetTime // returns time in 1/TICRATE second tics // +/* tic_t I_GetTime (void) { static Uint64 basetime = 0; @@ -2132,8 +2136,33 @@ tic_t I_GetTime (void) return (tic_t)ticks; } +*/ +int TimeFunction(boolean microseconds)// this cant actually do microseconds so it fakes it +{ + static Uint64 basetime = 0; + Uint64 ticks = SDL_GetTicks(); + + if (!basetime) + basetime = ticks; + + ticks -= basetime; + + return microseconds ? ticks * 1000 : ticks; +} #endif +tic_t I_GetTime(void) +{ + //return TimeFunction(false) / (1000/NEWTICRATE); + // how about this + return (TimeFunction(false) * NEWTICRATE) / 1000; +} + +int I_GetTimeMicros(void) +{ + return TimeFunction(true); +} + // //I_StartupTimer //