14 posts
Edited by Blu342 on Reason: Initial post
https://youtu.be/_4vnV2Eng7M?t=3802

"would you always orchestrate how you do threading in the platform layer or does it make sense for the platform layer to also provide a more generic threading job service?"

Casey's Answer, as linked in the video is that he prefers it to be orchestrated by the Platform/OS code.

I really did not get his answer/reasoning though or really what the question was asking? What exactly are the 2 options being debated here. I guess by Job system the questioner meant a ability for the actual game code to specify they wanted a certain operation to be multi-threaded (for example specific parts of a Physics simulation). But, Casey says this is bad because "threading often times in games is directly tied to resource management in a lot of places;" he says threads are often used to "service resource readiness," such as File IO, and thus should be wholly managed by the platform Layer. I do not get what he means by this. It seems like Casey is proposing that all multi-threading code should be entirely in the Platform Layer, but I don't even know how this could be achieved, since wouldn't the game actually be the thing that needs to multi-thread stuff (rendering, physics, etc) + i simply don't get how IO/Resource operations are actually related at all to wanting Thread code in the platform layer.
Simon Anciaux
1051 posts
I think the question was about whose responsibility is it to manage threads. Is it the platform layer, or the game layer.

If it's the responsibility of the platform, you have code that looks like this:
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* In the platform layer */ void thread_execute( ){ while ( true ){ wait_for_work( ); game_function( game_data ); /* This executes game code from the platform layer */ signal_finished( ); } } int platform_main( ){ threads t[ x ] = { 0 }; for ( int i = 0; i < x; i++ ) { t[ i ] = thread_create( ); } ... while ( running ) { game_update_and_render( ); } } /* In the game layer*/ int game_main( ){ ... platform_add_work_in_thread_queue( game_function, game_data ); ... } 

If it's the responsibility of the game:
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 /* In the platform layer*/ int thread_create( void thread_function( thread_data* ) ){ ... } int platform_main( ) { while ( running ) { game_update_and_render( ); } } /* In the game layer */ void game_thread_function( ) { while ( true ) { thread_wait_for_work( ); game_func( game_data ); thread_signal_finished( ); } } int game_main( ) { ... /* executed once */ thread t[x] = { 0 }; for ( int i = 0; i < x; i++ ) { thread_create( game_thread_function ); } /* when needed */ add_work_in_work_queue( game_func, game_data ); ... } 

The second case looks very similar to the first one, the changes are basically that some code switched from the platform layer to the game layer. But to allow that, the platform layer has to abstract how threads work on every platform we want the application to run on to provide a common API. Creating, waiting and signaling thread is pretty different on each platform, so it adds complexity when none is necessary.

Threading is used in two cases: when you need more performance and want to execute more instructions at the same time, or when you want to do some work without blocking the main thread. I/O is in that second case. You don't want your application to stop while you're loading your textures, or waiting for a network response. Here once again, the API between platform for asynchronous I/O is different so you don't want to abstract that.
14 posts