diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /unittests/ihvtest1 | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'unittests/ihvtest1')
| -rw-r--r-- | unittests/ihvtest1/ihvtest1.cpp | 1508 | ||||
| -rw-r--r-- | unittests/ihvtest1/ihvtest1.vpc | 106 | ||||
| -rw-r--r-- | unittests/ihvtest1/sys_clock.cpp | 254 |
3 files changed, 1868 insertions, 0 deletions
diff --git a/unittests/ihvtest1/ihvtest1.cpp b/unittests/ihvtest1/ihvtest1.cpp new file mode 100644 index 0000000..b1253dc --- /dev/null +++ b/unittests/ihvtest1/ihvtest1.cpp @@ -0,0 +1,1508 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +//============================================================================= + +#define PROTECTED_THINGS_DISABLE +#if !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif +#include <time.h> +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/IMaterialSystemHardwareConfig.h" +#include "materialsystem/imaterialproxyfactory.h" +#include "materialsystem/MaterialSystem_Config.h" +#include "appframework/appframework.h" +#include "datacache\idatacache.h" +#include "datacache\imdlcache.h" +#include "vphysics_interface.h" +#include "filesystem.h" +#include "IStudioRender.h" +#include "studio.h" +#include "clientstats.h" +#include "bone_setup.h" +#include "tier0/icommandline.h" +#include "vstdlib/cvar.h" +#include "tier0/vprof.h" +#include "tier1/tier1.h" +#include "optimize.h" +#if defined( _X360 ) +#include "xbox\xbox_console.h" +#include "xbox\xbox_win32stubs.h" +#endif + +//----------------------------------------------------------------------------- +// Main system interfaces +//----------------------------------------------------------------------------- +IMaterialSystem *g_pMaterialSystem = NULL; +IStudioRender *g_pStudioRender = NULL; +IFileSystem *g_pFileSystem = NULL; +IMDLCache *g_pMDLCache = NULL; + + +//----------------------------------------------------------------------------- +// App control defines +//----------------------------------------------------------------------------- +//#define MATERIAL_OVERRIDE +//#define USE_VTUNE +//#define USE_VPROF + +#if USE_VTUNE +#include "vtuneapi.h" +#endif + +static bool g_WindowMode = false; +static bool g_bUseEmptyShader = false; +static bool g_BenchFinished = false; +static bool g_BenchMode = false; +static bool g_SoftwareTL = false; + +static int g_RenderWidth = 640; +static int g_RenderHeight = 480; +static int g_RefreshRate = 60; +static int g_LOD = 0; +static int g_BodyGroup = 0; + +static int g_NumRows = 10; +static int g_NumCols = 10; + +static int g_dxLevel = 0; +static int g_LightingCombination = -1; + +static FILE *g_IHVTestFP = NULL; +static IMaterial *g_pForceMaterial = NULL; + +static bool g_bInError = false; + +#define MAX_LIGHTS 2 +#define NUM_LIGHT_TYPES 4 +#define LIGHTING_COMBINATION_COUNT 5 + +static const char *g_LightCombinationNames[] = +{ + "DISABLE ", +// "SPOT ", + "POINT ", + "DIRECTIONAL ", + "SPOT_SPOT ", +// "SPOT_POINT ", +// "SPOT_DIRECTIONAL ", +// "POINT_POINT ", + "POINT_DIRECTIONAL ", + "DIRECTIONAL_DIRECTIONAL" +}; + +//----------------------------------------------------------------------------- +// Test Model class +//----------------------------------------------------------------------------- +struct IHVTestModel +{ + MDLHandle_t hMdl; + studiohdr_t *pStudioHdr; + studiohwdata_t *pHardwareData; +}; + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CIHVTestApp : public CDefaultAppSystemGroup< CSteamAppSystemGroup > +{ +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void PostShutdown(); + virtual void Destroy(); + +private: + bool CreateAppWindow( char const *pTitle, int w, int h ); + void AppPumpMessages( void ); + void RenderFrame( void ); + void RenderScene( void ); + bool SetupMaterialSystem(); + bool SetupStudioRender(); + bool LoadModels( void ); + bool LoadModel( const char *pModelName, IHVTestModel *pModel ); + bool CreateMainWindow( int width, int height, bool fullscreen ); + matrix3x4_t* SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld, int iRun, int model, int boneMask ); + + // Windproc + static LONG WINAPI WinAppWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LONG WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + HWND m_hWnd; + bool m_bExitMainLoop; + + IHVTestModel *m_pIHVTestModel; +}; + +static CIHVTestApp s_IHVTestApp; +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT_GLOBALVAR( CIHVTestApp, s_IHVTestApp ); + +//----------------------------------------------------------------------------- +// Create the application window +//----------------------------------------------------------------------------- +bool CIHVTestApp::CreateAppWindow( const char* pAppName, int width, int height ) +{ + // Register the window class + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_CLASSDC; + wc.lpfnWndProc = WinAppWindowProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = pAppName; + wc.hIcon = NULL; + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Create the application's window + m_hWnd = CreateWindow( pAppName, pAppName, + WS_OVERLAPPEDWINDOW, + 0, 0, width, height, + GetDesktopWindow(), NULL, wc.hInstance, NULL ); + + ShowWindow (m_hWnd, SW_SHOWDEFAULT); + + return (m_hWnd != 0); +} + +//#define TREES + +// The maximum number of distinctive models each test may specify. +#ifdef TREES +const int g_nMaxModels = 1; +#else +const int g_nMaxModels = 9; +#endif + +//----------------------------------------------------------------------------- +// Benchmarking +//----------------------------------------------------------------------------- +struct BenchRunInfo +{ + const char *pModelName[g_nMaxModels]; + int numFrames; + int rows; + int cols; + float modelSize; + int sequence1[g_nMaxModels]; + int sequence2; +}; + +struct BenchResults +{ + BenchResults() : totalTime( 0.0f ), totalTris( 0 ) {} + float totalTime; + int totalTris; +}; + + +#define NUM_BENCH_RUNS 1 +static BenchResults g_BenchResults[NUM_BENCH_RUNS][LIGHTING_COMBINATION_COUNT]; + +#ifdef TREES + +#define MODEL_ROWS 13 +#define MODEL_COLUMNS 13 +static BenchRunInfo g_BenchRuns[NUM_BENCH_RUNS] = +{ + { { "models/props_foliage/tree_dead01.mdl" + }, 100, MODEL_ROWS, MODEL_COLUMNS, 1000.0f, { 0 }, -1 }, +}; + +#else + +#define MODEL_ROWS 3 +#define MODEL_COLUMNS 3 +static BenchRunInfo g_BenchRuns[NUM_BENCH_RUNS] = +{ + { { "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + }, 100, MODEL_ROWS, MODEL_COLUMNS, 75.0f, { 1, 4, 20, 23, 25, 30, 34, 38, 1 }, -1 }, +}; + +#endif + +// this is used in "-bench" mode +static IHVTestModel g_BenchModels[NUM_BENCH_RUNS][g_nMaxModels]; + +static void WriteBenchResults( void ) +{ + if( !g_BenchMode ) + { + return; + } + + FILE *fp = fopen( "ihvtest1.csv", "a+" ); + Assert( fp ); + if( !fp ) + { + return; + } + + fprintf( fp, "------------------------------------------------------------------\n" ); + + time_t ltime; + time( <ime ); + + fprintf( fp, "%s\n", GetCommandLine() ); + fprintf( fp, "Run at: %s", ctime( <ime ) ); + + int i; + for( i = 0; i < NUM_BENCH_RUNS; i++ ) + { + int j; + fprintf( fp, "model,light combo,total tris,total time,tris/sec\n" ); + for( j = 0; j < LIGHTING_COMBINATION_COUNT; j++ ) + { + int k; + for( k = 0; k < g_nMaxModels; k++ ) + { + if( g_BenchRuns[i].pModelName[k] ) + { + fprintf( fp, "%s%s", k ? ", " : "", g_BenchRuns[i].pModelName[k] ); + } + } + fprintf( fp, "," ); + fprintf( fp, "%s,", g_LightCombinationNames[j] ); + fprintf( fp, "%d,", g_BenchResults[i][j].totalTris ); + fprintf( fp, "%0.5f,", ( float )g_BenchResults[i][j].totalTime ); + fprintf( fp, "%0.0lf\n", ( double )g_BenchResults[i][j].totalTris / + ( double )g_BenchResults[i][j].totalTime ); + Warning( "%f %d\n", ( float )g_BenchResults[i][j].totalTime, g_BenchResults[i][j].totalTris ); + } + } + + fclose( fp ); +} + + +//----------------------------------------------------------------------------- +// Destroy app +//----------------------------------------------------------------------------- +void CIHVTestApp::Destroy() +{ + // Close the window + if (m_hWnd) + DestroyWindow( m_hWnd ); + + WriteBenchResults(); +} + + +//----------------------------------------------------------------------------- +// Window size helper +//----------------------------------------------------------------------------- +static void CalcWindowSize( int desiredRenderingWidth, int desiredRenderingHeight, + int *windowWidth, int *windowHeight ) +{ + int borderX, borderY; + borderX = (GetSystemMetrics(SM_CXFIXEDFRAME) + 1) * 2; + borderY = (GetSystemMetrics(SM_CYFIXEDFRAME) + 1) * 2 + GetSystemMetrics(SM_CYSIZE) + 1; + *windowWidth = desiredRenderingWidth + borderX; + *windowHeight = desiredRenderingHeight + borderY; +} + + +//----------------------------------------------------------------------------- +// Spew function! +//----------------------------------------------------------------------------- +SpewRetval_t IHVTestSpewFunc( SpewType_t spewType, char const *pMsg ) +{ + g_bInError = true; + + OutputDebugString( pMsg ); + switch( spewType ) + { + case SPEW_MESSAGE: + case SPEW_WARNING: + case SPEW_LOG: + OutputDebugString( pMsg ); + g_bInError = false; + return SPEW_CONTINUE; + + case SPEW_ASSERT: + case SPEW_ERROR: + default: + ::MessageBox( NULL, pMsg, "Error!", MB_OK ); + g_bInError = false; + return SPEW_DEBUGGER; + } +} + + +//----------------------------------------------------------------------------- +// Spew function to write to ihvtest_vprof.txt +//----------------------------------------------------------------------------- +SpewRetval_t IHVTestVProfSpewFunc( SpewType_t spewType, char const *pMsg ) +{ + g_bInError = true; + + switch( spewType ) + { + case SPEW_MESSAGE: + case SPEW_WARNING: + case SPEW_LOG: + fprintf( g_IHVTestFP, "%s", pMsg ); + g_bInError = false; + return SPEW_CONTINUE; + + case SPEW_ASSERT: + case SPEW_ERROR: + default: + ::MessageBox( NULL, pMsg, "Error!", MB_OK ); + g_bInError = false; + return SPEW_DEBUGGER; + } +} + +//----------------------------------------------------------------------------- +// Warnings and Errors... +//----------------------------------------------------------------------------- +#define MAXPRINTMSG 4096 +void DisplayError( const char* pError, ... ) +{ + va_list argptr; + char msg[1024]; + + g_bInError = true; + + va_start( argptr, pError ); + Q_vsnprintf( msg, sizeof( msg ), pError, argptr ); + va_end( argptr ); + + MessageBox( 0, msg, 0, MB_OK ); + + exit( -1 ); +} + +static void MaterialSystem_Warning( const char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof ( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} + +// garymcthack +static void MaterialSystem_Warning( char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} + +static void MaterialSystem_Error( char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + g_bInError = true; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + MessageBox( NULL, (LPCTSTR)msg, "MaterialSystem Fatal Error", MB_OK | MB_ICONINFORMATION ); + +#ifdef _DEBUG + Assert( 0 ); +#endif + exit( -1 ); +} + + +//----------------------------------------------------------------------------- +// Engine Stats +//----------------------------------------------------------------------------- +// itty bitty interface for stat time +class CStatTime : public IClientStatsTime +{ +public: + float GetTime() + { + return Sys_FloatTime(); + } +}; +CStatTime g_StatTime; + +class CEngineStats +{ +public: + CEngineStats() : m_InFrame( false ) {}; + // + // stats input + // + + void BeginRun( void ); + void BeginFrame( void ); + + void EndFrame( void ); + void EndRun( void ); + + // + // stats output + // call these outside of a BeginFrame/EndFrame pair + // + + // return the frame time in seconds for the whole system (not just graphics) + double GetCurrentSystemFrameTime( void ); + double GetRunTime( void ); +private: + // How many frames worth of data have we logged? + int m_totalNumFrames; + + // frame timing data + double m_frameStartTime; + double m_frameEndTime; + double m_minFrameTime; + double m_maxFrameTime; + + // run timing data + double m_runStartTime; + double m_runEndTime; + + bool m_InFrame; +}; + +void CEngineStats::BeginRun( void ) +{ + m_totalNumFrames = 0; + // frame timing data + m_runStartTime = Sys_FloatTime(); +} + +void CEngineStats::EndRun( void ) +{ + m_runEndTime = Sys_FloatTime(); +} + +void CEngineStats::BeginFrame( void ) +{ + m_InFrame = true; + m_frameStartTime = Sys_FloatTime(); +} + +void CEngineStats::EndFrame( void ) +{ + double deltaTime; + + m_frameEndTime = Sys_FloatTime(); + deltaTime = GetCurrentSystemFrameTime(); + + m_InFrame = false; +} + +double CEngineStats::GetRunTime( void ) +{ + return m_runEndTime - m_runStartTime; +} + +double CEngineStats::GetCurrentSystemFrameTime( void ) +{ + return m_frameEndTime - m_frameStartTime; +} +static CEngineStats g_EngineStats; + + +//----------------------------------------------------------------------------- +// Lighting +//----------------------------------------------------------------------------- +// If you change the number of lighting combinations, change LIGHTING_COMBINATION_COUNT +static LightType_t g_LightCombinations[][MAX_LIGHTS] = +{ + { MATERIAL_LIGHT_DISABLE, MATERIAL_LIGHT_DISABLE }, // 0 +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_DISABLE }, +// { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_DISABLE }, + { MATERIAL_LIGHT_DIRECTIONAL, MATERIAL_LIGHT_DISABLE }, + { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_SPOT }, + +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_POINT }, // 5 +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_DIRECTIONAL }, +// { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_POINT }, + { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_DIRECTIONAL }, + { MATERIAL_LIGHT_DIRECTIONAL, MATERIAL_LIGHT_DIRECTIONAL }, // 9 +}; + +LightDesc_t g_TestLights[NUM_LIGHT_TYPES][MAX_LIGHTS]; + +static void FixLight( LightDesc_t *pLight ) +{ + pLight->m_Range = 0.0f; + pLight->m_Falloff = 1.0f; + pLight->m_ThetaDot = cos( pLight->m_Theta * 0.5f ); + pLight->m_PhiDot = cos( pLight->m_Phi * 0.5f ); + pLight->m_Flags = 0; + if( pLight->m_Attenuation0 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; + } + if( pLight->m_Attenuation1 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1; + } + if( pLight->m_Attenuation2 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2; + } + VectorNormalize( pLight->m_Direction ); +} + + +static void InitTestLights( void ) +{ + LightDesc_t *pLight; + int i; + for( i = 0; i < MAX_LIGHTS; i++ ) + { + // MATERIAL_LIGHT_DISABLE + pLight = &g_TestLights[MATERIAL_LIGHT_DISABLE][i]; + pLight->m_Type = MATERIAL_LIGHT_DISABLE; + } + + // x - right + // y - up + // z - front of model + // MATERIAL_LIGHT_SPOT 0 + pLight = &g_TestLights[MATERIAL_LIGHT_SPOT][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_SPOT; + pLight->m_Color.Init( 5000.0f, 3500.0f, 3500.0f ); + pLight->m_Position.Init( 0.0f, 0.0f, 50.0f ); + pLight->m_Direction.Init( 0.0f, 0.5f, -1.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 1.0f / 10; + pLight->m_Theta = DEG2RAD( 20.0f ); + pLight->m_Phi = DEG2RAD( 30.0f ); + + // MATERIAL_LIGHT_SPOT 1 + pLight = &g_TestLights[MATERIAL_LIGHT_SPOT][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_SPOT; + pLight->m_Color.Init( 3500.0f, 5000.0f, 3500.0f ); + pLight->m_Position.Init( 0.0f, 0.0f, 150.0f ); + pLight->m_Direction.Init( 0.0f, 0.5f, -1.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 1.0f / 10; + pLight->m_Theta = DEG2RAD( 20.0f ); + pLight->m_Phi = DEG2RAD( 30.0f ); + + // MATERIAL_LIGHT_POINT 0 + pLight = &g_TestLights[MATERIAL_LIGHT_POINT][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_POINT; + pLight->m_Color.Init( 1500.0f, 750.0f, 750.0f ); + pLight->m_Position.Init( 200.0f, 200.0f, 200.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 1.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_POINT 1 + pLight = &g_TestLights[MATERIAL_LIGHT_POINT][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_POINT; + pLight->m_Color.Init( 750.0f, 750.0f, 1500.0f ); + pLight->m_Position.Init( -200.0f, 200.0f, 200.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 1.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_DIRECTIONAL 0 + pLight = &g_TestLights[MATERIAL_LIGHT_DIRECTIONAL][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_DIRECTIONAL; + pLight->m_Color.Init( 2.0f, 2.0f, 1.0f ); + pLight->m_Direction.Init( -1.0f, 0.0f, 0.0f ); + pLight->m_Attenuation0 = 1.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_DIRECTIONAL 1 + pLight = &g_TestLights[MATERIAL_LIGHT_DIRECTIONAL][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_DIRECTIONAL; + pLight->m_Color.Init( 1.0f, 1.0f, 2.0f ); + pLight->m_Direction.Init( 1.0f, 0.0f, 0.0f ); + pLight->m_Attenuation0 = 1.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 0.0f; + + for( i = 0; i < MAX_LIGHTS; i++ ) + { + int j; + for( j = 0; j < NUM_LIGHT_TYPES; j++ ) + { + FixLight( &g_TestLights[j][i] ); + } + } +} + + +//----------------------------------------------------------------------------- +// Setup lighting +//----------------------------------------------------------------------------- +static void SetupLighting( int lightingCombination, Vector &lightOffset ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + if( lightingCombination == 0 ) + { + g_pStudioRender->SetLocalLights( 0, NULL ); + pRenderContext->SetAmbientLight( 1.0, 1.0, 1.0 ); + + static Vector white[6] = + { + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + }; + g_pStudioRender->SetAmbientLightColors( white ); + } + else + { + pRenderContext->SetAmbientLight( 0.0f, 0.0f, 0.0f ); + + static Vector black[6] = + { + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + }; + g_pStudioRender->SetAmbientLightColors( black ); + + int lightID; + LightDesc_t lightDescs[MAX_LIGHTS]; + for( lightID = 0; lightID < MAX_LIGHTS; lightID++ ) + { + int lightType = g_LightCombinations[lightingCombination][lightID]; + lightDescs[lightID] = g_TestLights[lightType][lightID]; + lightDescs[lightID].m_Position += lightOffset; + } + + // Feed disabled lights through? + if( g_LightCombinations[lightingCombination][1] == MATERIAL_LIGHT_DISABLE ) + { + g_pStudioRender->SetLocalLights( 1, lightDescs ); + } + else + { + g_pStudioRender->SetLocalLights( MAX_LIGHTS, lightDescs ); + } + } +} + + +//----------------------------------------------------------------------------- +// Models +//----------------------------------------------------------------------------- +static float s_PoseParameter[32]; +static float s_Cycle[9] = { 0.0f }; + +virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const +{ + if ( numincludemodels == 0 ) + return NULL; + return g_pMDLCache->GetVirtualModelFast( this, (MDLHandle_t)virtualModel ); +} + +byte *studiohdr_t::GetAnimBlock( int i ) const +{ + return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i ); +} + +int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const +{ + return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut ); +} + +const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const +{ + return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache ); +} + + +//----------------------------------------------------------------------------- +// Set up the bones for a frame +//----------------------------------------------------------------------------- +matrix3x4_t* CIHVTestApp::SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld, int iRun, int model, int boneMask ) +{ + CStudioHdr studioHdr( pStudioHdr, g_pMDLCache ); + + // Default to middle of the pose parameter range + float flPoseParameter[MAXSTUDIOPOSEPARAM]; + Studio_CalcDefaultPoseParameters( &studioHdr, flPoseParameter, MAXSTUDIOPOSEPARAM ); + + int nFrameCount = Studio_MaxFrame( &studioHdr, g_BenchRuns[iRun].sequence1[model], flPoseParameter ); + if ( nFrameCount == 0 ) + { + nFrameCount = 1; + } + + Vector pos[MAXSTUDIOBONES]; + Quaternion q[MAXSTUDIOBONES]; + + IBoneSetup boneSetup( &studioHdr, boneMask, flPoseParameter ); + boneSetup.InitPose( pos, q ); + boneSetup.AccumulatePose( pos, q, g_BenchRuns[iRun].sequence1[model], s_Cycle[model], 1.0f, 0.0, NULL ); + + // FIXME: Try enabling this? +// CalcAutoplaySequences( pStudioHdr, NULL, pos, q, flPoseParameter, BoneMask( ), flTime ); + + // Root transform + matrix3x4_t rootToWorld, temp; + + MatrixCopy( shapeToWorld, rootToWorld ); + + matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() ); + for ( int i = 0; i < studioHdr.numbones(); i++ ) + { + // If it's not being used, fill with NAN for errors + if ( !(studioHdr.pBone( i )->flags & boneMask) ) + { + int j, k; + for (j = 0; j < 3; j++) + { + for (k = 0; k < 4; k++) + { + pBoneToWorld[i][j][k] = VEC_T_NAN; + } + } + continue; + } + + matrix3x4_t boneMatrix; + QuaternionMatrix( q[i], boneMatrix ); + MatrixSetColumn( pos[i], 3, boneMatrix ); + + if (studioHdr.pBone(i)->parent == -1) + { + ConcatTransforms (rootToWorld, boneMatrix, pBoneToWorld[i]); + } + else + { + ConcatTransforms (pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] ); + } + } + g_pStudioRender->UnlockBoneMatrices(); + return pBoneToWorld; +} + + +//----------------------------------------------------------------------------- +// Use mdlcache to load a model +//----------------------------------------------------------------------------- +bool CIHVTestApp::LoadModel( const char* pModelName, IHVTestModel *pModel ) +{ + pModel->hMdl = g_pMDLCache->FindMDL( pModelName ); + + pModel->pStudioHdr = g_pMDLCache->GetStudioHdr( pModel->hMdl ); + + g_pMDLCache->GetVertexData( pModel->hMdl ); + g_pMDLCache->FinishPendingLoads(); + + g_pMDLCache->GetHardwareData( pModel->hMdl ); + g_pMDLCache->FinishPendingLoads(); + + pModel->pHardwareData = g_pMDLCache->GetHardwareData( pModel->hMdl ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Loads all models +//----------------------------------------------------------------------------- +bool CIHVTestApp::LoadModels( void ) +{ + const char *pArgVal; + if( CommandLine()->CheckParm( "-rowcol", &pArgVal ) ) + { + g_NumRows = g_NumCols = atoi( pArgVal ); + } + + /* figure out which LOD we are going to render */ + if( CommandLine()->CheckParm( "-lod", &pArgVal ) ) + { + g_LOD = atoi( pArgVal ); + } + + if( CommandLine()->CheckParm( "-body", &pArgVal ) ) + { + g_BodyGroup = atoi( pArgVal ); + } + + // figure out g_RefreshRate + if( CommandLine()->CheckParm( "-refresh", &pArgVal ) ) + { + g_RefreshRate = atoi( pArgVal ); + } + + if( CommandLine()->CheckParm( "-light", &pArgVal ) ) + { + g_LightingCombination = atoi( pArgVal ); + if( g_LightingCombination < 0 ) + { + g_LightingCombination = 0; + } + if( g_LightingCombination >= LIGHTING_COMBINATION_COUNT ) + { + g_LightingCombination = LIGHTING_COMBINATION_COUNT - 1; + } + } + + g_pForceMaterial = g_pMaterialSystem->FindMaterial( "models/alyx/thigh", TEXTURE_GROUP_OTHER ); +#ifdef MATERIAL_OVERRIDE + g_pStudioRender->ForcedMaterialOverride( g_pForceMaterial ); +#endif + + InitTestLights(); + + if( g_BenchMode ) + { + int i; + for( i = 0; i < NUM_BENCH_RUNS; i++ ) + { + // Load each of the potentially alternating models: + int k; + for( k = 0; k < g_nMaxModels; k++ ) + { + if( g_BenchRuns[i].pModelName[k] ) + { + if( !LoadModel( g_BenchRuns[i].pModelName[k], &g_BenchModels[i][k] ) ) + { + return false; + } + } + } + } + } + else + { + CommandLine()->CheckParm( "-i", &pArgVal ); + if( !LoadModel( pArgVal, m_pIHVTestModel ) ) + { + return false; + } + } + g_pMaterialSystem->CacheUsedMaterials(); + + return true; +} + + +//----------------------------------------------------------------------------- +// App window proc +//----------------------------------------------------------------------------- +LONG CIHVTestApp::WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch( msg ) + { + // abort when ESC is hit + case WM_CHAR: + switch(wParam) + { + case VK_ESCAPE: + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + break; + } + break; + + case WM_DESTROY: + m_bExitMainLoop = true; + return 0; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + + +//----------------------------------------------------------------------------- +// Static registered window proc +//----------------------------------------------------------------------------- +LONG WINAPI CIHVTestApp::WinAppWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return s_IHVTestApp.WindowProc( hWnd, uMsg, wParam, lParam ); +} + + +//----------------------------------------------------------------------------- +// Pump messages +//----------------------------------------------------------------------------- +void CIHVTestApp::AppPumpMessages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + + +//----------------------------------------------------------------------------- +// Advance the frame +//----------------------------------------------------------------------------- +void AdvanceFrame( CStudioHdr *pStudioHdr, int iRun, int model, float dt ) +{ + if (dt > 0.1) + dt = 0.1f; + + float t = Studio_Duration( pStudioHdr, g_BenchRuns[iRun].sequence1[model], s_PoseParameter ); + + if (t > 0) + { + s_Cycle[model] += dt / t; + + // wrap + s_Cycle[model] -= (int)(s_Cycle[model]); + } + else + { + s_Cycle[model] = 0; + } +} + + +//----------------------------------------------------------------------------- +// Render a frame +//----------------------------------------------------------------------------- +void CIHVTestApp::RenderFrame( void ) +{ + VPROF( "RenderFrame" ); + IHVTestModel *pModel = NULL; + static int currentRun = 0; + static int currentFrame = 0; + static int currentLightCombo = 0; + int modelAlternator = 0; + + if (g_bInError) + { + // error context is active + // error may be renderer based, avoid re-entrant render to fatal crash + return; + } + + if( g_BenchMode ) + { + if( currentFrame > g_BenchRuns[currentRun].numFrames ) + { + currentLightCombo++; + if( currentLightCombo >= LIGHTING_COMBINATION_COUNT ) + { + currentRun++; + currentLightCombo = 0; + if( currentRun >= NUM_BENCH_RUNS ) + { + g_BenchFinished = true; + return; + } + } + currentFrame = 0; + } + } + if( g_BenchMode ) + { + pModel = &g_BenchModels[currentRun][0]; + g_NumCols = g_BenchRuns[currentRun].cols; + g_NumRows = g_BenchRuns[currentRun].rows; + } + else + { + pModel = m_pIHVTestModel; + } + Assert( pModel ); + + g_EngineStats.BeginFrame(); + + g_pMaterialSystem->BeginFrame( 0 ); + g_pStudioRender->BeginFrame(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->ClearColor3ub( 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true ); + + pRenderContext->Viewport( 0, 0, g_RenderWidth, g_RenderHeight ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->PerspectiveX( 90.0f, ( g_RenderWidth / g_RenderHeight), 1.0f, 500000.0f ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + if( g_BenchMode ) + { + pRenderContext->Translate( 0.0f, 0.0f, ( float )-( g_NumCols * g_BenchRuns[currentRun].modelSize * 0.6f ) ); + } + else + { + pRenderContext->Translate( 0.0f, 0.0f, ( float )-( g_NumCols * 80.0f * 0.5f ) ); + } + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity(); + + QAngle angles; + angles[YAW] = -90.0f; + angles[PITCH] = -90.0f; + angles[ROLL] = 0.0f; + + matrix3x4_t cameraMatrix; + AngleMatrix( angles, cameraMatrix ); + + int r, c; + int trisRendered = 0; + float boneSetupTime = 0.0f; + for( r = 0; r < g_NumRows; r++ ) + { + for( c = 0; c < g_NumCols; c++ ) + { + // If we are alternating models, select the next valid model. + if( g_BenchMode ) + { + do + { + // If I pass my maximum number of models, wrap around to model 0, which must always be valid. + if( ++modelAlternator >= g_nMaxModels ) + { + modelAlternator = 0; + break; + } + } + while( !g_BenchRuns[currentRun].pModelName[modelAlternator] ); + + pModel = &g_BenchModels[currentRun][modelAlternator]; + Assert( pModel ); + } + + if( g_BenchMode ) + { + cameraMatrix[0][3] = ( ( c + 0.5f ) - ( g_NumCols * .5f ) ) * g_BenchRuns[currentRun].modelSize; + cameraMatrix[1][3] = ( ( float )r - ( g_NumCols * .5f ) ) * g_BenchRuns[currentRun].modelSize; + } + else + { + cameraMatrix[0][3] = ( ( c + 0.5f ) - ( g_NumCols * .5f ) ) * 75.0f; + cameraMatrix[1][3] = ( ( float )r - ( g_NumCols * .5f ) ) * 75.0f; + } + + Vector modelOrigin( cameraMatrix[0][3], cameraMatrix[1][3], 0.0f ); + Vector lightOffset( cameraMatrix[0][3], cameraMatrix[1][3], 0.0f ); + + if (g_LightingCombination < 0) + { + SetupLighting( g_BenchMode ? currentLightCombo : 0, lightOffset ); + } + else + { + SetupLighting( g_LightingCombination, lightOffset ); + } + + float startBoneSetupTime = Sys_FloatTime(); + int lod = g_LOD; + lod = clamp( lod, pModel->pHardwareData->m_RootLOD, pModel->pHardwareData->m_NumLODs-1 ); + + int boneMask = BONE_USED_BY_VERTEX_AT_LOD( lod ); + matrix3x4_t *pBoneToWorld = SetUpBones( pModel->pStudioHdr, cameraMatrix, currentRun, modelAlternator, boneMask ); + boneSetupTime += Sys_FloatTime() - startBoneSetupTime; + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + + DrawModelInfo_t modelInfo; + memset( &modelInfo, 0, sizeof( modelInfo ) ); + modelInfo.m_pStudioHdr = pModel->pStudioHdr; + modelInfo.m_pHardwareData = pModel->pHardwareData; + modelInfo.m_Decals = STUDIORENDER_DECAL_INVALID; + modelInfo.m_Skin = 0; + modelInfo.m_Body = g_BodyGroup; + modelInfo.m_HitboxSet = 0; + modelInfo.m_pClientEntity = NULL; + modelInfo.m_Lod = lod; + modelInfo.m_pColorMeshes = NULL; + g_pStudioRender->DrawModel( NULL, modelInfo, pBoneToWorld, NULL, NULL, modelOrigin ); + + DrawModelResults_t results; + g_pStudioRender->GetPerfStats( &results, modelInfo, NULL ); + trisRendered += results.m_ActualTriCount; + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); + } + } + + pRenderContext->Flush( true ); + g_EngineStats.EndFrame(); + + g_pStudioRender->EndFrame(); + g_pMaterialSystem->EndFrame(); + + // hack - don't count the first frame in case there are any state + // transitions computed on that frame. + if( currentFrame != 0 ) + { + g_BenchResults[currentRun][currentLightCombo].totalTime += g_EngineStats.GetCurrentSystemFrameTime(); + g_BenchResults[currentRun][currentLightCombo].totalTris += trisRendered; + } + + for ( int model = 0; model < g_nMaxModels; ++model ) + { + CStudioHdr studioHdr( g_BenchModels[currentRun][model].pStudioHdr, g_pMDLCache ); + AdvanceFrame( &studioHdr, currentRun, model, g_EngineStats.GetCurrentSystemFrameTime() ); + } + + g_pMaterialSystem->SwapBuffers(); + +#ifdef USE_VPROF + g_VProfCurrentProfile.MarkFrame(); + static bool bBeenHere = false; + if( !bBeenHere ) + { + bBeenHere = true; + g_VProfCurrentProfile.Reset(); + } +#endif + currentFrame++; +} + + +//----------------------------------------------------------------------------- +// Create the application object +//----------------------------------------------------------------------------- +bool CIHVTestApp::Create() +{ + AppSystemInfo_t appSystems[] = + { + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, + { "datacache.dll", DATACACHE_INTERFACE_VERSION }, + { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION }, + { "datacache.dll", MDLCACHE_INTERFACE_VERSION }, + { "vphysics.dll", VPHYSICS_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + if ( !AddSystems( appSystems ) ) + return false; + + g_pFileSystem = ( IFileSystem * )FindSystem( FILESYSTEM_INTERFACE_VERSION ); + g_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + g_pStudioRender = (IStudioRender*)FindSystem( STUDIO_RENDER_INTERFACE_VERSION ); + g_pMDLCache = (IMDLCache*)FindSystem( MDLCACHE_INTERFACE_VERSION ); + + if ( !g_pFileSystem || !g_pMaterialSystem || !g_pStudioRender || !g_pMDLCache ) + { + DisplayError( "Unable to load required library interfaces!" ); + return false; + } + +#if defined( _X360 ) + // vxconsole - true will block (legacy behavior) + XBX_InitConsoleMonitor( false ); +#endif + + const char* pDLLName; + if ( CommandLine()->CheckParm( "-null" ) ) + { + g_bUseEmptyShader = true; + pDLLName = "shaderapiempty.dll"; + } + else + { + pDLLName = "shaderapidx9.dll"; + } + +#if defined( _X360 ) + g_pFileSystem->LoadModule( pDLLName ); +#endif + g_pMaterialSystem->SetShaderAPI( pDLLName ); + + return true; +} + + +//----------------------------------------------------------------------------- +// StudioRender... +//----------------------------------------------------------------------------- +bool CIHVTestApp::SetupStudioRender( void ) +{ + StudioRenderConfig_t config; + memset( &config, 0, sizeof(config) ); + + config.bEyeMove = true; + config.bTeeth = true; + config.bEyes = true; + config.bFlex = true; + + config.fEyeShiftX = 0.0f; + config.fEyeShiftY = 0.0f; + config.fEyeShiftZ = 0.0f; + config.fEyeSize = 0.0f; + + config.bNoHardware = false; + config.bNoSoftware = false; + + config.bSoftwareSkin = false; + config.bSoftwareLighting = false; + + config.drawEntities = true; + config.bWireframe = false; + config.bDrawNormals = false; + config.bDrawTangentFrame = false; + config.skin = 0; + + config.fullbright = 0; + + config.bShowEnvCubemapOnly = false; + + g_pStudioRender->UpdateConfig( config ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Material system +//----------------------------------------------------------------------------- +bool InitMaterialSystem( HWND mainWindow ) +{ + MaterialSystem_Config_t config; + if( g_WindowMode ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + } + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, IsX360() ? 0 : true ); + + config.m_VideoMode.m_Width = 0; + config.m_VideoMode.m_Height = 0; + config.m_VideoMode.m_Format = IMAGE_FORMAT_BGRX8888; + config.m_VideoMode.m_RefreshRate = g_RefreshRate; + config.dxSupportLevel = IsX360() ? 98 : 0; + + bool modeSet = g_pMaterialSystem->SetMode( (void*)mainWindow, config ); + if (!modeSet) + { + DisplayError( "Unable to set mode\n" ); + return false; + } + + g_pMaterialSystem->OverrideConfig( config, false ); + + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit +//----------------------------------------------------------------------------- +bool CIHVTestApp::PreInit( void ) +{ + CreateInterfaceFn factory = GetFactory(); + ConnectTier1Libraries( &factory, 1 ); + + // Add paths... + if ( !SetupSearchPaths( NULL, false, true ) ) + { + Error( "Failed to setup search paths\n" ); + return false; + } + + const char *pArgVal; + if ( CommandLine()->CheckParm( "-bench" ) ) + { + g_BenchMode = true; + } + + if( !g_BenchMode && !CommandLine()->CheckParm( "-i" ) ) + { + // Set some default parameters for running as a unittest + g_BenchMode = true; + g_WindowMode = IsPC() ? true : false; + } + + if( g_BenchMode ) + { + if ( CommandLine()->CheckParm( "-i", &pArgVal ) ) + { + g_BenchRuns[0].pModelName[0] = pArgVal; + } + } + + if( CommandLine()->CheckParm( "-softwaretl" ) ) + { + g_SoftwareTL = true; + } + + // Explicitly in window/fullscreen mode? + if ( CommandLine()->CheckParm( "-window") ) + { + g_WindowMode = true; + } + else if ( CommandLine()->CheckParm( "-fullscreen" ) ) + { + g_WindowMode = false; + } + + /* figure out g_Renderwidth and g_RenderHeight */ + g_RenderWidth = -1; + g_RenderHeight = -1; + + if( CommandLine()->CheckParm( "-width", &pArgVal ) ) + { + g_RenderWidth = atoi( pArgVal ); + } + if( CommandLine()->CheckParm( "-height", &pArgVal ) ) + { + g_RenderHeight = atoi( pArgVal ); + } + + if( g_RenderWidth == -1 && g_RenderHeight == -1 ) + { + g_RenderWidth = 640; + g_RenderHeight = 480; + } + else if( g_RenderWidth != -1 && g_RenderHeight == -1 ) + { + switch( g_RenderWidth ) + { + case 320: + g_RenderHeight = 240; + break; + case 512: + g_RenderHeight = 384; + break; + case 640: + g_RenderHeight = 480; + break; + case 800: + g_RenderHeight = 600; + break; + case 1024: + g_RenderHeight = 768; + break; + case 1280: + g_RenderHeight = 1024; + break; + case 1600: + g_RenderHeight = 1200; + break; + default: + DisplayError( "Can't figure out window dimensions!!" ); + exit( -1 ); + break; + } + } + + if( g_RenderWidth == -1 || g_RenderHeight == -1 ) + { + DisplayError( "Can't figure out window dimensions!!" ); + exit( -1 ); + } + + int windowWidth, windowHeight; + CalcWindowSize( g_RenderWidth, g_RenderHeight, &windowWidth, &windowHeight ); + + if( !CreateAppWindow( "ihvtest1", windowWidth, windowHeight ) ) + { + return false; + } + return true; +} + +void CIHVTestApp::PostShutdown() +{ + DisconnectTier1Libraries(); +} + + +//----------------------------------------------------------------------------- +// The application main loop +//----------------------------------------------------------------------------- +int CIHVTestApp::Main() +{ + SpewOutputFunc( IHVTestSpewFunc ); + + if ( !SetupStudioRender() ) + { + return 0; + } + + if ( !InitMaterialSystem( m_hWnd ) ) + { + return 0; + } + +#if !defined( _X360 ) // X360TBD: +extern void Sys_InitFloatTime( void ); //garymcthack + Sys_InitFloatTime(); +#endif + + LoadModels(); + +#if USE_VTUNE + VTResume(); +#endif +#ifdef USE_VPROF + g_VProfCurrentProfile.Start(); +#endif + + bool m_bExitMainLoop = false; + while (!m_bExitMainLoop && !g_BenchFinished) + { + AppPumpMessages(); + RenderFrame(); + } + +#ifdef USE_VPROF + g_VProfCurrentProfile.Stop(); +#endif + g_IHVTestFP = fopen( "ihvtest_vprof.txt", "w" ); +#ifdef USE_VPROF + SpewOutputFunc( IHVTestVProfSpewFunc ); + g_VProfCurrentProfile.OutputReport( VPRT_SUMMARY ); + g_VProfCurrentProfile.OutputReport( VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY ); + fclose( g_IHVTestFP ); + SpewOutputFunc( IHVTestSpewFunc ); +#endif +#if USE_VTUNE + VTPause(); +#endif + + return 0; +} + diff --git a/unittests/ihvtest1/ihvtest1.vpc b/unittests/ihvtest1/ihvtest1.vpc new file mode 100644 index 0000000..80731ca --- /dev/null +++ b/unittests/ihvtest1/ihvtest1.vpc @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// IHVTEST1.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared" + $PreprocessorDefinitions "$BASE;IHVTEST" + } +} + +$Project "ihvtest1" +{ + $Folder "Source Files" + { + $File "$SRCDIR\public\bone_setup.cpp" + $File "$SRCDIR\public\collisionutils.cpp" + $File "ihvtest1.cpp" + $File "$SRCDIR\public\studio.cpp" + $File "sys_clock.cpp" [$WIN32] + } + + $Folder "Public Header Files" + { + $File "$SRCDIR\public\mathlib\amd3dx.h" + $File "$SRCDIR\public\basehandle.h" + $File "$SRCDIR\public\tier0\basetypes.h" + $File "$SRCDIR\public\bitvec.h" + $File "$SRCDIR\public\bone_accessor.h" + $File "$SRCDIR\public\bone_setup.h" + $File "$SRCDIR\public\bspflags.h" + $File "$SRCDIR\public\clientstats.h" + $File "$SRCDIR\public\cmodel.h" + $File "$SRCDIR\public\CollisionUtils.h" + $File "$SRCDIR\public\tier0\commonmacros.h" + $File "$SRCDIR\public\mathlib\compressed_vector.h" + $File "$SRCDIR\public\const.h" + $File "$SRCDIR\public\tier0\dbg.h" + $File "$SRCDIR\public\tier0\fasttimer.h" + $File "$SRCDIR\public\filesystem.h" + $File "$SRCDIR\public\gametrace.h" + $File "$SRCDIR\public\appframework\IAppSystem.h" + $File "$SRCDIR\public\tier0\icommandline.h" + $File "$SRCDIR\public\ihandleentity.h" + $File "$SRCDIR\public\materialsystem\imaterialproxyfactory.h" + $File "$SRCDIR\public\materialsystem\imaterialsystem.h" + $File "$SRCDIR\public\materialsystem\imaterialsystemhardwareconfig.h" + $File "$SRCDIR\public\tier1\interface.h" + $File "$SRCDIR\public\istudiorender.h" + $File "$SRCDIR\public\materialsystem\materialsystem_config.h" + $File "$SRCDIR\public\mathlib\mathlib.h" + $File "$SRCDIR\public\tier0\mem.h" + $File "$SRCDIR\public\tier0\memalloc.h" + $File "$SRCDIR\public\tier0\memdbgon.h" + $File "$SRCDIR\public\tier0\platform.h" + $File "$SRCDIR\public\tier0\protected_things.h" + $File "$SRCDIR\public\vstdlib\random.h" + $File "$SRCDIR\public\string_t.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "$SRCDIR\public\studio.h" + $File "$SRCDIR\public\tier1\utlbuffer.h" + $File "$SRCDIR\public\tier1\utldict.h" + $File "$SRCDIR\public\tier1\utlmemory.h" + $File "$SRCDIR\public\tier1\utlrbtree.h" + $File "$SRCDIR\public\tier1\utlsymbol.h" + $File "$SRCDIR\public\tier1\utlvector.h" + $File "$SRCDIR\public\vcollide.h" + $File "$SRCDIR\public\mathlib\vector.h" + $File "$SRCDIR\public\mathlib\vector2d.h" + $File "$SRCDIR\public\mathlib\vector4d.h" + $File "$SRCDIR\public\tier0\vprof.h" + $File "$SRCDIR\public\vstdlib\vstdlib.h" + } + + $Folder "Build Bat Files" [$0] + { + $File "copybin.bat" + $File "copycommonsrc.bat" + $File "copydx8.bat" + $File "copygamesharedsrc.bat" + $File "copyihvtestsrc.bat" + $File "copylib.bat" + $File "copymatsyssrc.bat" + $File "copypublicsrc.bat" + $File "copyshaderdx8src.bat" + $File "copysrc.bat" + $File "copystudiorendersrc.bat" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib mathlib + $Lib $LIBCOMMON\vtuneapi [$WIN32&&!$VS2015] + $Lib $SRCDIR\lib\common\vtuneapi [$WIN32&&$VS2015] + } +} diff --git a/unittests/ihvtest1/sys_clock.cpp b/unittests/ihvtest1/sys_clock.cpp new file mode 100644 index 0000000..4412ed8 --- /dev/null +++ b/unittests/ihvtest1/sys_clock.cpp @@ -0,0 +1,254 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#include <assert.h> + +#pragma optimize( "", off ) + +#pragma pack( push, thing ) +#pragma pack( 4 ) +static long g_cw, g_single_cw, g_highchop_cw, g_full_cw, g_ceil_cw, g_pushed_cw; +static struct +{ + long dummy[8]; +} g_fpenv; +#pragma pack( pop, thing ) + + +void __declspec ( naked ) MaskExceptions() +{ + _asm + { + fnstenv ds:dword ptr[g_fpenv] + or ds:dword ptr[g_fpenv],03Fh + fldenv ds:dword ptr[g_fpenv] + ret + } +} + +void __declspec ( naked ) Sys_SetFPCW() +{ + _asm + { + fnstcw ds:word ptr[g_cw] + mov eax,ds:dword ptr[g_cw] + and ah,0F0h + or ah,003h + mov ds:dword ptr[g_full_cw],eax + mov ds:dword ptr[g_highchop_cw],eax + and ah,0F0h + or ah,00Ch + mov ds:dword ptr[g_single_cw],eax + and ah,0F0h + or ah,008h + mov ds:dword ptr[g_ceil_cw],eax + ret + } +} + +void __declspec ( naked ) Sys_PushFPCW_SetHigh() +{ + _asm + { + fnstcw ds:word ptr[g_pushed_cw] + fldcw ds:word ptr[g_full_cw] + ret + } +} + +void __declspec ( naked ) Sys_PopFPCW() +{ + _asm + { + fldcw ds:word ptr[g_pushed_cw] + ret + } +} + +#pragma optimize( "", on ) + +//----------------------------------------------------------------------------- +// Purpose: Implements high precision clock +// TODO: Make into an interface? +//----------------------------------------------------------------------------- +class CSysClock +{ +public: + // Construction + CSysClock( void ); + + // Initialization + void Init( void ); + void SetStartTime( void ); + + // Sample the clock + double GetTime( void ); + +private: + // High performance clock frequency + double m_dClockFrequency; + // Current accumulated time + double m_dCurrentTime; + // How many bits to shift raw 64 bit sample count by + int m_nTimeSampleShift; + // Previous 32 bit sample count + unsigned int m_uiPreviousTime; + + bool m_bInitialized; +}; + +static CSysClock g_Clock; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSysClock::CSysClock( void ) +{ + m_bInitialized = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize the clock +//----------------------------------------------------------------------------- +void CSysClock::Init( void ) +{ + BOOL success; + LARGE_INTEGER PerformanceFreq; + unsigned int lowpart, highpart; + + MaskExceptions (); + Sys_SetFPCW (); + + // Start clock at zero + m_dCurrentTime = 0.0; + + success = QueryPerformanceFrequency( &PerformanceFreq ); + assert( success ); + + // get 32 out of the 64 time bits such that we have around + // 1 microsecond resolution + lowpart = (unsigned int)PerformanceFreq.LowPart; + highpart = (unsigned int)PerformanceFreq.HighPart; + + m_nTimeSampleShift = 0; + + while ( highpart || ( lowpart > 2000000.0 ) ) + { + m_nTimeSampleShift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + m_dClockFrequency = 1.0 / (double)lowpart; + + // Get initial sample + unsigned int temp; + LARGE_INTEGER PerformanceCount; + QueryPerformanceCounter( &PerformanceCount ); + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // Set first time stamp + m_uiPreviousTime = temp; + + m_bInitialized = true; + + SetStartTime(); +} + +void CSysClock::SetStartTime( void ) +{ + GetTime(); + + m_dCurrentTime = 0.0; + + m_uiPreviousTime = ( unsigned int )m_dCurrentTime; +} + +double CSysClock::GetTime( void ) +{ + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + if ( !m_bInitialized ) + { + return 0.0; + } + + Sys_PushFPCW_SetHigh(); + + // Get sample counter + QueryPerformanceCounter( &PerformanceCount ); + + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // check for turnover or backward time + if ( ( temp <= m_uiPreviousTime ) && + ( ( m_uiPreviousTime - temp ) < 0x10000000) ) + { + m_uiPreviousTime = temp; // so we can't get stuck + } + else + { + // gap in performance clocks + t2 = temp - m_uiPreviousTime; + + // Convert to time using frequencey of clock + time = (double)t2 * m_dClockFrequency; + + // Remember old time + m_uiPreviousTime = temp; + + // Increment clock + m_dCurrentTime += time; + } + + Sys_PopFPCW(); + + // Convert to float + return m_dCurrentTime; + +} + +//----------------------------------------------------------------------------- +// Purpose: Sample the high-precision clock +// Output : double +//----------------------------------------------------------------------------- +double Sys_FloatTime( void ) +{ + return g_Clock.GetTime(); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize high-precision clock +//----------------------------------------------------------------------------- +void Sys_InitFloatTime( void ) +{ + g_Clock.Init(); +} |