/*
- .-. VG Event loop
+ .-. VG Event loop
| 0 |
-| | .-----------.
-|API| | vg_enter |
-| | '-----------'
+| | .---------------------------------------------------------.
+|API| | vg_enter( int argc, char *argv[], const char *window_name |
+| | '---------------------------------------------------------'
| | |
| | v
|IMP| vg_launch_opt(void) <--.
|IMP| | |.------------- vg_start(void) ---------------'
| | | |
| | | v
-|IMP| | vg_update( int loaded )
+|IMP| | vg_update(void)
| | | |
| | | .-----+.
| | | | |
| | | | v
-|IMP| | '- vg_update_fixed( int loaded )
+|IMP| | '- vg_update_fixed(void)
| | | |
| | | .-'
| | | |
|IMP| | vg_ui(void)
| | | |
| | '----'
+'___'
+
+ .-.
+| ? |
+| | .-------------------------------------.
+|API| | vg_fatal_exit_loop( const char *err ) |
+| | '-------------------------------------'
+| | |
+| | .------+.
+| | | |
+| | | v
+|IMP| '- vg_framebuffer_resize(void)
'___'
*/
VG_STATIC void vg_start(void);
VG_STATIC void vg_framebuffer_resize(int w, int h);
-VG_STATIC void vg_update(int loaded);
-VG_STATIC void vg_update_fixed(int loaded);
-VG_STATIC void vg_update_post(int loaded);
+VG_STATIC void vg_update(void);
+VG_STATIC void vg_update_fixed(void);
+VG_STATIC void vg_update_post(void);
VG_STATIC void vg_render(void);
VG_STATIC void vg_ui(void);
SDL_threadID thread_id_main,
thread_id_loader,
thread_id_with_opengl_context;
- int context_ownership_refcount;
+ int context_ownership_depth;
int exec_context;
engine_stage;
/* graphics */
+#if 0
m4x4f pv;
+#endif
enum quality_profile
{
k_quality_profile_high = 0,
}
VG_STATIC vg = { .time_rate = 1.0 };
-struct vg_thread_info
+enum vg_thread_purpose
{
- enum vg_thread_purpose
- {
- k_thread_purpose_nothing,
- k_thread_purpose_main,
- k_thread_purpose_loader
- }
- purpose;
-
- int gl_context_level;
+ k_thread_purpose_nothing,
+ k_thread_purpose_main,
+ k_thread_purpose_loader
};
VG_STATIC void vg_fatal_exit_loop( const char *error );
-VG_STATIC void vg_required( void *ptr, const char *path )
-{
- if( !ptr )
- {
- vg_fatal_exit_loop( path );
- }
-}
-VG_STATIC void vg_ensure_engine_running(void)
+/*
+ * Checks if the engine is running
+ */
+VG_STATIC void _vg_ensure_engine_running(void)
{
- VG_SYNC_LOG( "[%d] Checks if engine is running\n" );
-
/* Check if the engine is no longer running */
SDL_AtomicLock( &vg.sl_context );
+ enum engine_status status = vg.engine_status;
+ SDL_AtomicUnlock( &vg.sl_context );
- if( vg.engine_status != k_engine_status_running )
+ if( status != k_engine_status_running )
{
- VG_SYNC_LOG( "[%d] Engine is no longer running\n");
-
- /* Safe to disregard loader thread from this point on, elswhere */
- if( vg.thread_id_loader == SDL_GetThreadID(NULL) )
+ while(1)
{
- SDL_SemPost( vg.sem_loader );
+ VG_SYNC_LOG( "[%d] No longer running...\n");
+ SDL_Delay(1000);
}
-
- SDL_AtomicUnlock( &vg.sl_context );
-
- VG_SYNC_LOG( "[%d] is just going to hang around and wait to die\n");
- while(1) SDL_Delay(1000);
}
-
- SDL_AtomicUnlock( &vg.sl_context );
}
-/*
- * Sync execution so that the OpenGL context is switched onto this thread.
- * Anything after this call will be in a valid context.
- */
-VG_STATIC void vg_acquire_thread_sync(void)
+VG_STATIC enum vg_thread_purpose vg_thread_purpose(void)
{
- VG_SYNC_LOG( "[%d] Starts acquiring sync\n" );
-
- /* We dont want to do anything if this is the main thread */
SDL_AtomicLock( &vg.sl_context );
+
if( vg.thread_id_main == SDL_GetThreadID(NULL) )
{
SDL_AtomicUnlock( &vg.sl_context );
- return;
+ return k_thread_purpose_main;
}
- SDL_AtomicUnlock( &vg.sl_context );
-
- vg_ensure_engine_running();
-
- /* Check if thread already has the context */
- SDL_AtomicLock( &vg.sl_context );
- if( vg.thread_id_with_opengl_context == SDL_GetThreadID(NULL) )
+ else
{
- vg.context_ownership_refcount ++;
SDL_AtomicUnlock( &vg.sl_context );
-
- VG_SYNC_LOG( "[%d] We already have sync here\n" );
- return;
+ return k_thread_purpose_loader;
}
+}
- VG_SYNC_LOG( "[%d] Signal to sync.\n" );
- vg.exec_context = 1;
- SDL_AtomicUnlock( &vg.sl_context );
-
- /* wait until told we can go */
- VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n" );
-
- SDL_SemWait( vg.sem_allow_exec );
- SDL_GL_MakeCurrent( vg.window, vg.gl_context );
+/*
+ * Sync execution so that the OpenGL context is switched onto this thread.
+ * Anything after this call will be in a valid context.
+ */
+VG_STATIC void vg_acquire_thread_sync(void)
+{
+ /* We dont want to do anything if this is the main thread */
- VG_SYNC_LOG( "[%d] Allow exec passed\n" );
+ if( vg_thread_purpose() == k_thread_purpose_loader )
+ {
+ VG_SYNC_LOG( "[%d] vg_acquire_thread_sync()\n" );
+ _vg_ensure_engine_running();
- /* context now valid to work in while we hold up main thread */
- SDL_AtomicLock( &vg.sl_context );
- vg.context_ownership_refcount ++;
- SDL_AtomicUnlock( &vg.sl_context );
+ SDL_AtomicLock( &vg.sl_context );
+ if( vg.context_ownership_depth == 0 )
+ {
+ vg.context_ownership_depth ++;
+ vg.exec_context = 1;
+ SDL_AtomicUnlock( &vg.sl_context );
+
+ /* wait until told we can go */
+ VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n" );
+ SDL_SemWait( vg.sem_allow_exec );
+
+ _vg_ensure_engine_running();
- VG_SYNC_LOG( "[%d] Context acquired.\n" );
+ SDL_GL_MakeCurrent( vg.window, vg.gl_context );
+ VG_SYNC_LOG( "[%d] granted\n" );
+ }
+ else
+ {
+ vg.context_ownership_depth ++;
+ VG_SYNC_LOG( "[%d] granted\n" );
+ SDL_AtomicUnlock( &vg.sl_context );
+ }
+ }
}
/*
*/
VG_STATIC void vg_release_thread_sync(void)
{
- VG_SYNC_LOG( "[%d] Releases sync\n" );
-
- SDL_AtomicLock( &vg.sl_context );
- if( vg.thread_id_main == SDL_GetThreadID(NULL) )
- {
- SDL_AtomicUnlock( &vg.sl_context );
- return;
- }
-
- /* signal that we are done */
- vg.context_ownership_refcount --;
- if( !vg.context_ownership_refcount )
+ if( vg_thread_purpose() == k_thread_purpose_loader )
{
- SDL_AtomicUnlock( &vg.sl_context );
+ VG_SYNC_LOG( "[%d] vg_release_thread_sync()\n" );
- VG_SYNC_LOG( "[%d] Releasing context.\n" );
+ SDL_AtomicLock( &vg.sl_context );
+ vg.context_ownership_depth --;
- SDL_GL_MakeCurrent( NULL, NULL );
- SDL_SemPost( vg.sem_exec_finished );
+ if( vg.context_ownership_depth == 0 )
+ {
+ SDL_AtomicUnlock( &vg.sl_context );
+ VG_SYNC_LOG( "[%d] Releasing context.\n" );
+ SDL_GL_MakeCurrent( NULL, NULL );
+ SDL_SemPost( vg.sem_exec_finished );
+ }
+ else
+ SDL_AtomicUnlock( &vg.sl_context );
}
- else
- SDL_AtomicUnlock( &vg.sl_context );
}
-VG_STATIC void vg_run_synced_content(void)
+VG_STATIC void _vg_run_synced(void)
{
SDL_AtomicLock( &vg.sl_context );
if( vg.exec_context != 0 )
{
- VG_SYNC_LOG( "[%d] Allowing content (%d).\n", vg.exec_context );
+ VG_SYNC_LOG( "[%d] _vg_run_synced() (%d).\n", vg.exec_context );
vg.exec_context = 0;
SDL_AtomicUnlock( &vg.sl_context );
SDL_SemWait( vg.sem_exec_finished );
/* check if we killed the engine */
- vg_ensure_engine_running();
+ _vg_ensure_engine_running();
/* re-engage main thread */
VG_SYNC_LOG( "[%d] Re-engaging.\n" );
SDL_GL_MakeCurrent( vg.window, vg.gl_context );
}
else
+ {
+ VG_SYNC_LOG( "[%d] Nothing to do.\n" );
SDL_AtomicUnlock( &vg.sl_context );
+ }
}
-VG_STATIC void vg_opengl_sync_init(void)
+VG_STATIC void _vg_opengl_sync_init(void)
{
vg.sem_allow_exec = SDL_CreateSemaphore(0);
vg.sem_exec_finished = SDL_CreateSemaphore(0);
vg_release_thread_sync();
}
-VG_STATIC void vg_load_full(void)
+VG_STATIC void _vg_load_full(void)
{
vg_preload();
/* internal */
- vg_loader_highwater( vg_input_init, vg_input_free, NULL );
- vg_loader_highwater( vg_lines_init, NULL, NULL );
- vg_loader_highwater( vg_audio_init, vg_audio_free, NULL );
- vg_loader_highwater( vg_profiler_init, NULL, NULL );
+ vg_loader_step( vg_input_init, vg_input_free );
+ vg_loader_step( vg_lines_init, NULL );
+ vg_loader_step( vg_audio_init, vg_audio_free );
+ vg_loader_step( vg_profiler_init, NULL );
/* client */
vg_load();
-
- vg_acquire_thread_sync();
- vg.is_loaded = 1;
- vg_release_thread_sync();
}
-VG_STATIC void vg_process_events(void)
+VG_STATIC void _vg_process_events(void)
{
/* Update timers */
vg.time_real_last = vg.time_real;
vg_update_inputs();
}
-VG_STATIC void vg_gameloop_update( int post_start )
+VG_STATIC void _vg_gameloop_update(void)
{
vg_profile_begin( &vg_prof_update );
vg.engine_stage = k_engine_stage_update;
- vg_update( post_start );
+ vg_update();
/* Fixed update loop */
vg.engine_stage = k_engine_stage_update_fixed;
vg_lines.allow_input = 1;
while( vg.accumulator >= (VG_TIMESTEP_FIXED-0.00125) )
{
- vg_update_fixed( post_start );
+ vg_update_fixed();
vg_lines.allow_input = 0;
vg.accumulator -= VG_TIMESTEP_FIXED;
vg_lines.allow_input = 1;
vg.engine_stage = k_engine_stage_update;
- vg_update_post( post_start );
+ vg_update_post();
vg_profile_end( &vg_prof_update );
}
-VG_STATIC void vg_gameloop_render( int post_start )
+VG_STATIC void _vg_gameloop_render(void)
{
vg_profile_begin( &vg_prof_render );
- if( post_start )
+ if( vg.is_loaded )
{
/* render */
vg.engine_stage = k_engine_stage_rendering;
ui_text( (ui_rect){258, 4+24+12,0,0},perf, 1,0);
}
+ /* FIXME */
+#if 0
audio_debug_ui( vg.pv );
+#endif
vg_ui();
- vg_console_draw();
+ _vg_console_draw();
ui_resolve();
ui_draw( NULL );
vg_profile_end( &vg_prof_render );
}
-VG_STATIC void vg_gameloop(void)
+VG_STATIC void _vg_gameloop(void)
{
vg.accumulator = 0.75f * (1.0f/60.0f);
int post_start = 0;
while(1)
{
- vg_process_events();
+ _vg_process_events();
if( vg.window_should_close )
break;
}
else
{
- vg_loader_render();
+ _vg_loader_render();
}
- vg_gameloop_update( post_start );
- vg_gameloop_render( post_start );
+ _vg_gameloop_update();
+ _vg_gameloop_render();
+ audio_push_console_vol();
SDL_GL_SwapWindow( vg.window );
- vg_run_synced_content();
+ _vg_run_synced();
}
}
-VG_STATIC void vg_process_launch_opts_internal(void)
+VG_STATIC void _vg_process_launch_opts_internal( int argc, char *argv[] )
{
char *arg;
while( vg_argp( argc, argv ) )
if( vg_long_opt( "use-libc-malloc" ) )
{
- vg_mem.use_libc_malloc = atoi( arg );
+ vg_mem.use_libc_malloc = 1;
}
if( vg_long_opt( "high-performance" ) )
}
}
-VG_STATIC void vg_init_window(void)
+VG_STATIC void _vg_init_window( const char *window_name )
{
- if( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_GAMECONTROLLER) != 0 )
+ vg_info( "SDL_INIT\n" );
+
+ if( SDL_Init( SDL_INIT_VIDEO ) != 0 )
{
vg_error( "SDL_Init failed: %s\n", SDL_GetError() );
exit(0);
}
- SDL_GL_SetSwapInterval( 1 );
+ SDL_InitSubSystem( SDL_INIT_AUDIO );
+ SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER );
+
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE );
- SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 1 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
+ SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH );
+
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 );
- if( vg.samples > 1 )
- {
- SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
- SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, vg.samples );
- }
-
- SDL_GL_SetAttribute( SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
- SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH );
-
/*
* Get monitor information
*/
+ vg_info( "Getting display count\n" );
int display_count = 0, display_index = 0, mode_index = 0;
if( (display_count = SDL_GetNumVideoDisplays()) < 1 )
{
}
/* TODO: Allow chosing the modes at startup */
+ vg_info( "Getting display mode\n" );
SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
if( SDL_GetDisplayMode( display_index, mode_index, &mode ) != 0 )
{
vg.refresh_rate = mode.refresh_rate;
+ if( !vg.window_x )
+ vg.window_x = mode.w;
+
+ if( !vg.window_y )
+ vg.window_y = mode.h;
+
+ vg_info( "CreateWindow( %d %d )\n", vg.window_x, vg.window_y );
+
/* TODO: Allow selecting closest video mode from launch opts */
if((vg.window = SDL_CreateWindow( window_name,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
- mode.w, mode.h,
+ vg.window_x, vg.window_y,
- SDL_WINDOW_FULLSCREEN |
+ SDL_WINDOW_FULLSCREEN_DESKTOP |
SDL_WINDOW_OPENGL |
SDL_WINDOW_INPUT_GRABBED )))
{
exit(0);
}
+ vg_info( "CreateContext\n" );
+
/*
* OpenGL loading
*/
const unsigned char* glver = glGetString( GL_VERSION );
vg_success( "Load setup complete, OpenGL version: %s\n", glver );
+
+ vg_info( "Setting swap interval\n" );
+
+ if( SDL_GL_SetSwapInterval( -1 ) == -1 )
+ {
+ vg_warn( "Adaptive Vsync not supported\n" );
+
+ if( SDL_GL_SetSwapInterval( 1 ) == -1 )
+ {
+ vg_fatal_exit_loop( "Cannot enable Vsync! You might be overriding it"
+ " in your graphics control panel.\n" );
+ }
+ else
+ vg_success( "Using vsync\n" );
+ }
+ else
+ vg_success( "Using adaptive Vsync\n" );
+
+ SDL_DisplayMode dispmode;
+ if( !SDL_GetWindowDisplayMode( vg.window, &dispmode ) )
+ {
+ if( dispmode.refresh_rate )
+ {
+ vg.refresh_rate = dispmode.refresh_rate;
+ vg_info( "Refresh rate: %d\n", dispmode.refresh_rate );
+ }
+ }
}
VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name )
{
- vg_process_launch_opts_internal();
+ _vg_process_launch_opts_internal( argc, argv );
/* Systems init */
vg_alloc_quota();
- vg_log_init();
- vg_console_init();
- vg_init_window();
+ _vg_log_init();
+ _vg_console_init();
+ _vg_init_window( window_name );
SDL_SetRelativeMouseMode(1);
vg.thread_id_main = SDL_GetThreadID(NULL);
/* Opengl-required systems */
- ui_init_context();
- vg_loader_init();
+ _vg_ui_init();
+ _vg_loader_init();
vg.engine_status = k_engine_status_running;
- vg_opengl_sync_init();
- vg_loader_start();
-
- /* main */
- vg_gameloop();
+ _vg_opengl_sync_init();
+ vg_loader_start( _vg_load_full );
+ _vg_gameloop();
/* Shutdown */
- vg_console_write_persistent();
+ _vg_console_write_persistent();
SDL_AtomicLock( &vg.sl_context );
vg.engine_status = k_engine_status_none;
SDL_AtomicUnlock( &vg.sl_context );
- vg_loader_free();
+ _vg_loader_free();
vg_success( "If you see this it means everything went.. \"well\".....\n" );
else
{
SDL_AtomicUnlock( &vg.sl_context );
-
- /*
- * if main
- * if loader running
- * wait until loader checks in, it will die
- * else
- * pass immediately
- * else
- * if have context
- * pass immediately
- * else
- * wait for main to get to us, it will never be used again
- *
- * undefined behaviour:
- * fatal_exit_loop is called in both threads, preventing an appropriate
- * reaction to the crash. This *should* be made
- * obvious by the assertion
- */
+
vg_acquire_thread_sync();
- SDL_AtomicUnlock( &vg.sl_context );
+ SDL_AtomicLock( &vg.sl_context );
vg.engine_status = k_engine_status_crashed;
vg.str_const_engine_err = error;
+ SDL_AtomicUnlock( &vg.sl_context );
- /*
- * Wait for loader to finish what it was doing, if it was running.
- * Then we can continue in our nice error screen
- */
- if( vg.thread_id_main == SDL_GetThreadID(NULL) )
+ /* Notify other thread for curtosey */
+ if( vg_thread_purpose() == k_thread_purpose_main )
{
+ SDL_AtomicLock( &vg.sl_context );
+
+ if( vg.exec_context != 0 )
+ SDL_SemPost( vg.sem_allow_exec );
+
SDL_AtomicUnlock( &vg.sl_context );
- SDL_SemWait( vg.sem_loader );
}
- else
- SDL_AtomicUnlock( &vg.sl_context );
- vg_audio_free(NULL);
+ vg_audio_free();
while(1)
{
- vg_process_events();
+ _vg_process_events();
if( vg.window_should_close )
break;
glBlendEquation(GL_FUNC_ADD);
glClearColor( 0.15f + sinf(vg.time_real)*0.1f, 0.0f, 0.0f,1.0f );
- glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
+ glClear( GL_COLOR_BUFFER_BIT );
glViewport( 0,0, vg.window_x, vg.window_y );
- vg_render_log();
+ _vg_render_log();
SDL_GL_SwapWindow( vg.window );
}
/* Can now shutdown and EXIT */
- vg_loader_free();
+ _vg_loader_free();
SDL_GL_DeleteContext( vg.gl_context );
SDL_Quit();
exit(0);