/***************************************************************************** ** ** ** Neversoft Entertainment ** ** ** ** Copyright (C) 1999 - All Rights Reserved ** ** ** ****************************************************************************** ** ** ** Project: GEL (Game Engine Library) ** ** ** ** Module: Main Loop (ML) ** ** ** ** File name: mainloop.cpp ** ** ** ** Created: 05/27/99 - mjb ** ** ** ** Description: Main loop and support code ** ** ** *****************************************************************************/ /***************************************************************************** ** Includes ** *****************************************************************************/ #include #include #include #include #include #ifndef __PLAT_WN32__ #include #endif #include #ifdef __PLAT_NGPS__ #include #include namespace NxPs2 { void WaitForRendering(); void StuffAfterGSFinished(); } #endif /***************************************************************************** ** DBG Information ** *****************************************************************************/ Dbg_DefineProject( GEL, "GEL Library" ) namespace Mdl { void Rail_DebugRender(); // for debugging } namespace Mlp { /***************************************************************************** ** Externals ** *****************************************************************************/ /***************************************************************************** ** Defines ** *****************************************************************************/ /***************************************************************************** ** Private Types ** *****************************************************************************/ /***************************************************************************** ** Private Data ** *****************************************************************************/ DefineSingletonClass( Manager, "Main Loop Manager" ); /***************************************************************************** ** Public Data ** *****************************************************************************/ /***************************************************************************** ** Private Prototypes ** *****************************************************************************/ /***************************************************************************** ** Private Functions ** *****************************************************************************/ Manager::Manager( void ) { start_render_hook = NULL; end_render_hook = NULL; done = false; } /******************************************************************/ /* */ /* */ /******************************************************************/ Manager::~Manager( void ) { } /******************************************************************/ /* */ /* */ /******************************************************************/ inline void Manager::service_system( void ) { #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 255, 0, 0 ); # endif // __USE_PROFILER__ #endif system_task_stack.Process (currently_profiling); #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext(); # endif // __USE_PROFILER__ #endif } /******************************************************************/ /* */ /* */ /******************************************************************/ inline void Manager::game_logic( void ) { #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 0, 255, 0 ); # endif // __USE_PROFILER__ #endif // printf ("\nTiming Logic\n"); logic_task_stack.Process(currently_profiling); // printf ("\nDumping Task List\n\n"); // logic_task_stack.Dump(); #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext(); # endif // __USE_PROFILER__ #endif } /******************************************************************/ /* */ /* */ /******************************************************************/ inline void Manager::render_frame( void ) { // printf ("############################## render_frame #############################\n"); #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 0, 0, 255 ); # endif // __USE_PROFILER__ #endif # ifdef __PLAT_NGC__ if( start_render_hook ) { start_render_hook->Call(); } if( !display_tasks_paused ) { display_task_stack.Process( currently_profiling ); } # else if (!display_tasks_paused) { // If paused don't call the start_render_hook // as this clears the none-visible frame buffer // which will result in a flash when display is unpaused if ( start_render_hook ) // set up for rendering { start_render_hook->Call(); } // printf ("\nTiming render\n"); display_task_stack.Process(currently_profiling); // service rendering routines } # endif // __PLAT_NGC__ #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext(); Sys::CPUProfiler->PushContext( 255, 255, 0 ); # endif // __USE_PROFILER__ #endif if ( end_render_hook ) // end rendering { end_render_hook->Call(); } #ifndef __PLAT_WN32__ # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext(); # endif // __USE_PROFILER__ #endif } /***************************************************************************** ** Public Functions ** *****************************************************************************/ void Manager::MainLoop( void ) { bool old_flag = done; // push the current done flag done = false; while ( !done ) { if (trigger_profiling) { printf ("\nProfiling.....Start of main loop\n\n"); trigger_profiling--; currently_profiling = 1; } #ifndef __PLAT_WN32__ #ifdef __PLAT_NGPS__ // for profiling on the PS2, we do a bit of the code from sPreRender here // so we can time the final waiting for GS # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 0,0,255 ); // blue = wait for VU/DMA/GPU to finish # endif NxPs2::WaitForRendering(); // PS2 Specific, wait for prior frame's DMA to finish NxPs2::StuffAfterGSFinished(); // PS2 Specific, DMA altering stuff run after previous frame's DMA finished # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext( ); Sys::CPUProfiler->PushContext( 128,0,0 ); // red = wait for vblank # endif int framerate = Script::GetInteger(0x3214c818/*"lock_framerate"*/); if (framerate) // normal vsync { static uint64 next_vblanks= 0; // Still call VSync, as it updates some functions Tmr::VSync(); while (Tmr::GetVblanks()PopContext( ); # endif #endif #ifndef __PLAT_NGC__ # ifdef __USE_PROFILER__ Sys::Profiler::sStartFrame(); # endif #endif Nx::CEngine::sPreRender(); // start rendering previous frame's DMA list #ifdef __PLAT_NGPS__ Sfx::CSpuManager::sUpdateStatus(); // Garrett: This should go into some system task, but I'll put it here for now #endif // Sys::Profiler::sStartFrame(); #endif #ifdef __PLAT_NGC__ # ifdef __USE_PROFILER__ Sys::Profiler::sStartFrame(); # endif # endif service_system(); #if defined(__PLAT_NGPS__) && defined(BATCH_TRI_COLLISION) // Enable VU0 collision bool got_vu0 = Nx::CBatchTriCollMan::sUseVU0Micro(); Dbg_Assert(got_vu0); #endif #ifdef __PLAT_NGPS__ // snProfSetRange( -1, (void*)0, (void*)-1); // snProfSetFlagValue(0x01); #endif game_logic(); #ifdef __PLAT_NGPS__ // snProfSetRange( 4, (void*)NULL, (void*)-1); #endif #if defined(__PLAT_NGPS__) && defined(BATCH_TRI_COLLISION) // Disable VU0 collision if (got_vu0) { Nx::CBatchTriCollMan::sDisableVU0Micro(); } #endif #ifndef __PLAT_WN32__ // Display the memory contents, (if memview is active) MemView_Display(); # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 255, 255, 0 ); // yellow = render world # endif #ifdef __PLAT_NGPS__ // snProfSetRange( -1, (void*)0, (void*)-1); // snProfSetFlagValue(0x01); #endif Nx::CEngine::sRenderWorld(); #ifdef __PLAT_NGC__ #ifdef __USE_PROFILER__ Sys::Render_Profiler(); #endif #endif // Mick: bit of a patch here, we need some better debug hooks Mdl::Rail_DebugRender(); # ifdef __USE_PROFILER__ Sys::CPUProfiler->PushContext( 0, 0, 0 ); // Black (Under Yellow) = sPostRender # endif // __USE_PROFILER__ Nx::CEngine::sPostRender(); // Previous frames profiler is rendered here # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext( ); # endif # ifdef __USE_PROFILER__ Sys::CPUProfiler->PopContext( ); # endif Tmr::OncePerRender(); #ifdef __PLAT_NGPS__ // snProfSetRange( 4, (void*)NULL, (void*)-1); #endif #endif currently_profiling = false; } done = old_flag; } void Manager::ProfileTasks(int n) { trigger_profiling = n; currently_profiling = 0; } /******************************************************************/ /* */ /* */ /******************************************************************/ void Manager::QuitLoop( void ) { Dbg_Notify( "Exiting..." ); done = true; } /******************************************************************/ /* */ /* */ /******************************************************************/ void Manager::DoGameLogic( void ) { game_logic(); } /******************************************************************/ /* */ /* */ /******************************************************************/ } // namespace Mlp