const char* idSysLocal::FPU_GetState() { return Sys_FPU_GetState(); }
/* ================== WinMain ================== */ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { const HCURSOR hcurSave = ::SetCursor(LoadCursor(0, IDC_WAIT)); Sys_SetPhysicalWorkMemory(192 << 20, 1024 << 20); Sys_GetCurrentMemoryStatus(exeLaunchMemoryStats); #if 0 DWORD handler = (DWORD)_except_handler; __asm { // Build EXCEPTION_REGISTRATION record: push handler // Address of handler function push FS:[0] // Address of previous handler mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION } #endif win32.hInstance = hInstance; idStr::Copynz(sys_cmdline, lpCmdLine, sizeof(sys_cmdline)); // done before Com/Sys_Init since we need this for error output Sys_CreateConsole(); // no abort/retry/fail errors SetErrorMode(SEM_FAILCRITICALERRORS); for (int i = 0; i < MAX_CRITICAL_SECTIONS; i++) { InitializeCriticalSection(&win32.criticalSections[i]); } // get the initial time base Sys_Milliseconds(); #ifdef DEBUG // disable the painfully slow MS heap check every 1024 allocs _CrtSetDbgFlag(0); #endif // Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); Sys_FPU_SetPrecision(FPU_PRECISION_DOUBLE_EXTENDED); common->Init(0, NULL, lpCmdLine); #if TEST_FPU_EXCEPTIONS != 0 common->Printf(Sys_FPU_GetState()); #endif #ifndef ID_DEDICATED if (win32.win_notaskkeys.GetInteger()) { DisableTaskKeys(TRUE, FALSE, /*( win32.win_notaskkeys.GetInteger() == 2 )*/ FALSE); } #endif Sys_StartAsyncThread(); // hide or show the early console as necessary if (win32.win_viewlog.GetInteger() || com_skipRenderer.GetBool() || idAsyncNetwork::serverDedicated.GetInteger()) { Sys_ShowConsole(1, true); } else { Sys_ShowConsole(0, false); } #ifdef SET_THREAD_AFFINITY // give the main thread an affinity for the first cpu SetThreadAffinityMask(GetCurrentThread(), 1); #endif ::SetCursor(hcurSave); // Launch the script debugger if (strstr(lpCmdLine, "+debugger")) { // DebuggerClientInit( lpCmdLine ); return 0; } ::SetFocus(win32.hWnd); // main game loop while (1) { Win_Frame(); #ifdef DEBUG Sys_MemFrame(); #endif // set exceptions, even if some crappy syscall changes them! Sys_FPU_EnableExceptions(TEST_FPU_EXCEPTIONS); #ifdef ID_ALLOW_TOOLS if (com_editors) { if (com_editors & EDITOR_GUI) { // GUI editor GUIEditorRun(); } else if (com_editors & EDITOR_RADIANT) { // Level Editor RadiantRun(); } else if (com_editors & EDITOR_MATERIAL) { //BSM Nerve: Add support for the material editor MaterialEditorRun(); } else { if (com_editors & EDITOR_LIGHT) { // in-game Light Editor LightEditorRun(); } if (com_editors & EDITOR_SOUND) { // in-game Sound Editor SoundEditorRun(); } if (com_editors & EDITOR_DECL) { // in-game Declaration Browser DeclBrowserRun(); } if (com_editors & EDITOR_AF) { // in-game Articulated Figure Editor AFEditorRun(); } if (com_editors & EDITOR_PARTICLE) { // in-game Particle Editor ParticleEditorRun(); } if (com_editors & EDITOR_SCRIPT) { // in-game Script Editor ScriptEditorRun(); } if (com_editors & EDITOR_PDA) { // in-game PDA Editor PDAEditorRun(); } } } #endif // run the game common->Frame(); } // never gets here return 0; }
/* ================== WinMain ================== */ int main(int argc, char *argv[]) { const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) ); Sys_SetPhysicalWorkMemory( 192 << 20, 1024 << 20 ); win32.hInstance = GetModuleHandle(NULL); // done before Com/Sys_Init since we need this for error output Sys_CreateConsole(); // no abort/retry/fail errors SetErrorMode( SEM_FAILCRITICALERRORS ); #ifdef DEBUG // disable the painfully slow MS heap check every 1024 allocs _CrtSetDbgFlag( 0 ); #endif // Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); Sys_FPU_SetPrecision( FPU_PRECISION_DOUBLE_EXTENDED ); if ( argc > 1 ) { common->Init( argc-1, &argv[1] ); } else { common->Init( 0, NULL ); } #if TEST_FPU_EXCEPTIONS != 0 common->Printf( Sys_FPU_GetState() ); #endif // hide or show the early console as necessary if ( win32.win_viewlog.GetInteger() || com_skipRenderer.GetBool() || idAsyncNetwork::serverDedicated.GetInteger() ) { Sys_ShowConsole( 1, true ); } else { Sys_ShowConsole( 0, false ); } #ifdef SET_THREAD_AFFINITY // give the main thread an affinity for the first cpu SetThreadAffinityMask( GetCurrentThread(), 1 ); #endif ::SetCursor( hcurSave ); // Launch the script debugger if ( strstr( GetCommandLine(), "+debugger" ) ) { // DebuggerClientInit( lpCmdLine ); return 0; } ::SetFocus( win32.hWnd ); // main game loop while( 1 ) { Win_Frame(); // set exceptions, even if some crappy syscall changes them! Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); #ifdef ID_ALLOW_TOOLS if ( com_editors ) { if ( com_editors & EDITOR_GUI ) { // GUI editor GUIEditorRun(); } else if ( com_editors & EDITOR_RADIANT ) { // Level Editor RadiantRun(); } else if (com_editors & EDITOR_MATERIAL ) { //BSM Nerve: Add support for the material editor MaterialEditorRun(); } else { if ( com_editors & EDITOR_LIGHT ) { // in-game Light Editor LightEditorRun(); } if ( com_editors & EDITOR_SOUND ) { // in-game Sound Editor SoundEditorRun(); } if ( com_editors & EDITOR_DECL ) { // in-game Declaration Browser DeclBrowserRun(); } if ( com_editors & EDITOR_AF ) { // in-game Articulated Figure Editor AFEditorRun(); } if ( com_editors & EDITOR_PARTICLE ) { // in-game Particle Editor ParticleEditorRun(); } if ( com_editors & EDITOR_SCRIPT ) { // in-game Script Editor ScriptEditorRun(); } if ( com_editors & EDITOR_PDA ) { // in-game PDA Editor PDAEditorRun(); } } } #endif // run the game common->Frame(); } // never gets here return 0; }
/* ================= idCommonLocal::Frame ================= */ void idCommonLocal::Frame() { try { SCOPED_PROFILE_EVENT( "Common::Frame" ); // This is the only place this is incremented idLib::frameNumber++; // allow changing SIMD usage on the fly if ( com_forceGenericSIMD.IsModified() ) { idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() ); com_forceGenericSIMD.ClearModified(); } // Do the actual switch between Doom 3 and the classics here so // that things don't get confused in the middle of the frame. PerformGameSwitch(); // pump all the events Sys_GenerateEvents(); // write config file if anything changed WriteConfiguration(); eventLoop->RunEventLoop(); // Activate the shell if it's been requested if ( showShellRequested && game ) { game->Shell_Show( true ); showShellRequested = false; } // if the console or another gui is down, we don't need to hold the mouse cursor bool chatting = false; if ( console->Active() || Dialog().IsDialogActive() || session->IsSystemUIShowing() || ( game && game->InhibitControls() && !IsPlayingDoomClassic() ) ) { Sys_GrabMouseCursor( false ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true ); chatting = true; } else { Sys_GrabMouseCursor( true ); usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false ); } const bool pauseGame = ( !mapSpawned || ( !IsMultiplayer() && ( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || ( game && game->Shell_IsActive() ) ) ) ) && !IsPlayingDoomClassic(); // save the screenshot and audio from the last draw if needed if ( aviCaptureMode ) { idStr name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviDemoFrameCount++ ); renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); // remove any printed lines at the top before taking the screenshot console->ClearNotifyLines(); // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1 renderSystem->TakeScreenshot( com_aviDemoWidth.GetInteger(), com_aviDemoHeight.GetInteger(), name, com_aviDemoSamples.GetInteger(), NULL ); } //-------------------------------------------- // wait for the GPU to finish drawing // // It is imporant to minimize the time spent between this // section and the call to renderSystem->RenderCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // this should exit right after vsync, with the GPU idle and ready to draw // This may block if the GPU isn't finished renderng the previous frame. frameTiming.startSyncTime = Sys_Microseconds(); const emptyCommand_t * renderCommands = NULL; if ( com_smp.GetBool() ) { renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } else { // the GPU will stay idle through command generation for minimal // input latency renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } frameTiming.finishSyncTime = Sys_Microseconds(); //-------------------------------------------- // Determine how many game tics we are going to run, // now that the previous frame is completely finished. // // It is important that any waiting on the GPU be done // before this, or there will be a bad stuttering when // dropping frames for performance management. //-------------------------------------------- // input: // thisFrameTime // com_noSleep // com_engineHz // com_fixedTic // com_deltaTimeClamp // IsMultiplayer // // in/out state: // gameFrame // gameTimeResidual // lastFrameTime // syncNextFrame // // Output: // numGameFrames // How many game frames to run int numGameFrames = 0; for(;;) { const int thisFrameTime = Sys_Milliseconds(); static int lastFrameTime = thisFrameTime; // initialized only the first time const int deltaMilliseconds = thisFrameTime - lastFrameTime; lastFrameTime = thisFrameTime; // if there was a large gap in time since the last frame, or the frame // rate is very very low, limit the number of frames we will run const int clampedDeltaMilliseconds = Min( deltaMilliseconds, com_deltaTimeClamp.GetInteger() ); gameTimeResidual += clampedDeltaMilliseconds * timescale.GetFloat(); // don't run any frames when paused if ( pauseGame ) { gameFrame++; gameTimeResidual = 0; break; } // debug cvar to force multiple game tics if ( com_fixedTic.GetInteger() > 0 ) { numGameFrames = com_fixedTic.GetInteger(); gameFrame += numGameFrames; gameTimeResidual = 0; break; } if ( syncNextGameFrame ) { // don't sleep at all syncNextGameFrame = false; gameFrame++; numGameFrames++; gameTimeResidual = 0; break; } for ( ;; ) { // How much time to wait before running the next frame, // based on com_engineHz const int frameDelay = FRAME_TO_MSEC( gameFrame + 1 ) - FRAME_TO_MSEC( gameFrame ); if ( gameTimeResidual < frameDelay ) { break; } gameTimeResidual -= frameDelay; gameFrame++; numGameFrames++; // if there is enough residual left, we may run additional frames } if ( numGameFrames > 0 ) { // ready to actually run them break; } // if we are vsyncing, we always want to run at least one game // frame and never sleep, which might happen due to scheduling issues // if we were just looking at real time. if ( com_noSleep.GetBool() ) { numGameFrames = 1; gameFrame += numGameFrames; gameTimeResidual = 0; break; } // not enough time has passed to run a frame, as might happen if // we don't have vsync on, or the monitor is running at 120hz while // com_engineHz is 60, so sleep a bit and check again Sys_Sleep( 0 ); } //-------------------------------------------- // It would be better to push as much of this as possible // either before or after the renderSystem->SwapCommandBuffers(), // because the GPU is completely idle. //-------------------------------------------- // Update session and syncronize to the new session state after sleeping session->UpdateSignInManager(); session->Pump(); session->ProcessSnapAckQueue(); if ( session->GetState() == idSession::LOADING ) { // If the session reports we should be loading a map, load it! ExecuteMapChange(); mapSpawnData.savegameFile = NULL; mapSpawnData.persistentPlayerInfo.Clear(); return; } else if ( session->GetState() != idSession::INGAME && mapSpawned ) { // If the game is running, but the session reports we are not in a game, disconnect // This happens when a server disconnects us or we sign out LeaveGame(); return; } if ( mapSpawned && !pauseGame ) { if ( IsClient() ) { RunNetworkSnapshotFrame(); } } ExecuteReliableMessages(); // send frame and mouse events to active guis GuiFrameEvents(); //-------------------------------------------- // Prepare usercmds and kick off the game processing // in a background thread //-------------------------------------------- // get the previous usercmd for bypassed head tracking transform const usercmd_t previousCmd = usercmdGen->GetCurrentUsercmd(); // build a new usercmd int deviceNum = session->GetSignInManager().GetMasterInputDevice(); usercmdGen->BuildCurrentUsercmd( deviceNum ); if ( deviceNum == -1 ) { for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) { Sys_PollJoystickInputEvents( i ); Sys_EndJoystickInputEvents(); } } if ( pauseGame ) { usercmdGen->Clear(); } usercmd_t newCmd = usercmdGen->GetCurrentUsercmd(); // Store server game time - don't let time go past last SS time in case we are extrapolating if ( IsClient() ) { newCmd.serverGameMilliseconds = std::min( Game()->GetServerGameTimeMs(), Game()->GetSSEndTime() ); } else { newCmd.serverGameMilliseconds = Game()->GetServerGameTimeMs(); } userCmdMgr.MakeReadPtrCurrentForPlayer( Game()->GetLocalClientNum() ); // Stuff a copy of this userCmd for each game frame we are going to run. // Ideally, the usercmds would be built in another thread so you could // still get 60hz control accuracy when the game is running slower. for ( int i = 0 ; i < numGameFrames ; i++ ) { newCmd.clientGameMilliseconds = FRAME_TO_MSEC( gameFrame-numGameFrames+i+1 ); userCmdMgr.PutUserCmdForPlayer( game->GetLocalClientNum(), newCmd ); } // If we're in Doom or Doom 2, run tics and upload the new texture. if ( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() ) ) { RunDoomClassicFrame(); } // start the game / draw command generation thread going in the background gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames ); if ( !com_smp.GetBool() ) { // in non-smp mode, run the commands we just generated, instead of // frame-delayed ones from a background thread renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers(); } //---------------------------------------- // Run the render back end, getting the GPU busy with new commands // ASAP to minimize the pipeline bubble. //---------------------------------------- frameTiming.startRenderTime = Sys_Microseconds(); renderSystem->RenderCommandBuffers( renderCommands ); if ( com_sleepRender.GetInteger() > 0 ) { // debug tool to test frame adaption Sys_Sleep( com_sleepRender.GetInteger() ); } frameTiming.finishRenderTime = Sys_Microseconds(); // make sure the game / draw thread has completed // This may block if the game is taking longer than the render back end gameThread.WaitForThread(); // Send local usermds to the server. // This happens after the game frame has run so that prediction data is up to date. SendUsercmds( Game()->GetLocalClientNum() ); // Now that we have an updated game frame, we can send out new snapshots to our clients session->Pump(); // Pump to get updated usercmds to relay SendSnapshots(); // Render the sound system using the latest commands from the game thread if ( pauseGame ) { soundWorld->Pause(); soundSystem->SetPlayingSoundWorld( menuSoundWorld ); } else { soundWorld->UnPause(); soundSystem->SetPlayingSoundWorld( soundWorld ); } soundSystem->Render(); // process the game return for map changes, etc ProcessGameReturn( ret ); idLobbyBase & lobby = session->GetActivePlatformLobbyBase(); if ( lobby.HasActivePeers() ) { if ( net_drawDebugHud.GetInteger() == 1 ) { lobby.DrawDebugNetworkHUD(); } if ( net_drawDebugHud.GetInteger() == 2 ) { lobby.DrawDebugNetworkHUD2(); } lobby.DrawDebugNetworkHUD_ServerSnapshotMetrics( net_drawDebugHud.GetInteger() == 3 ); } // report timing information if ( com_speeds.GetBool() ) { static int lastTime = Sys_Milliseconds(); int nowTime = Sys_Milliseconds(); int com_frameMsec = nowTime - lastTime; lastTime = nowTime; Printf( "frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld\n", idLib::frameNumber, com_frameMsec, time_gameFrame, time_frontend / 1000, time_backend / 1000 ); time_gameFrame = 0; time_gameDraw = 0; } // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack if ( !Sys_FPU_StackIsEmpty() ) { Printf( Sys_FPU_GetState() ); FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" ); } mainFrameTiming = frameTiming; session->GetSaveGameManager().Pump(); } catch( idException & ) { return; // an ERP_DROP was thrown } }
/* ================== WinMain ================== */ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) ); Sys_SetPhysicalWorkMemory( 192 << 20, 1024 << 20 ); Sys_GetCurrentMemoryStatus( exeLaunchMemoryStats ); #if 0 DWORD handler = (DWORD)_except_handler; __asm { // Build EXCEPTION_REGISTRATION record: push handler // Address of handler function push FS:[0] // Address of previous handler mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION } #endif win32.hInstance = hInstance; idStr::Copynz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) ); // done before Com/Sys_Init since we need this for error output Sys_CreateConsole(); // no abort/retry/fail errors SetErrorMode( SEM_FAILCRITICALERRORS ); for ( int i = 0; i < MAX_CRITICAL_SECTIONS; i++ ) { InitializeCriticalSection( &win32.criticalSections[i] ); } // make sure the timer is high precision, otherwise // NT gets 18ms resolution timeBeginPeriod( 1 ); // get the initial time base Sys_Milliseconds(); #ifdef DEBUG // disable the painfully slow MS heap check every 1024 allocs _CrtSetDbgFlag( 0 ); #endif // Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); Sys_FPU_SetPrecision( FPU_PRECISION_DOUBLE_EXTENDED ); common->Init( 0, NULL, lpCmdLine ); #if TEST_FPU_EXCEPTIONS != 0 common->Printf( Sys_FPU_GetState() ); #endif if ( win32.win_notaskkeys.GetInteger() ) { DisableTaskKeys( TRUE, FALSE, /*( win32.win_notaskkeys.GetInteger() == 2 )*/ FALSE ); } // hide or show the early console as necessary if ( win32.win_viewlog.GetInteger() ) { Sys_ShowConsole( 1, true ); } else { Sys_ShowConsole( 0, false ); } #ifdef SET_THREAD_AFFINITY // give the main thread an affinity for the first cpu SetThreadAffinityMask( GetCurrentThread(), 1 ); #endif ::SetCursor( hcurSave ); ::SetFocus( win32.hWnd ); // main game loop while( 1 ) { Win_Frame(); #ifdef DEBUG Sys_MemFrame(); #endif // set exceptions, even if some crappy syscall changes them! Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); // run the game common->Frame(); } // never gets here return 0; }