Download presentation
Presentation is loading. Please wait.
Published byErick Holmes Modified over 8 years ago
1
Game Developers Conference 2009 Multithreaded AI For The Win! Orion Granatir Senior Software Engineer
2
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
3
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
4
Multi-core Needs Parallel Applications Challenge The number of cores is increasing To really maximize performance and features, a game needs to fully utilize the CPU This means threading! GHz EraMulti-core Era APP PERFORMANCE TIME PLATFORM POTENTIAL PERFORMANCE Parallel Serial Challenge
5
Distributing work among cores means more monsters! Core Challenge
6
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
7
Game Main Loop... Let’s define a simple AI Simple AI Graphics Physics AI A simple game loop that updates in a serial manner Each AI has a state machine that makes decisions and triggers collisions and pathfinding queries as needed AI State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding
8
AI_SPAWN Let’s define some states case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } Simple AI
9
AI_IDLE Let’s define some states case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } Simple AI
10
AI_ATTACK Let’s define some states case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision:: FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } Simple AI
11
case AI_EXPLODE: { // Find a path to the player Collision::Result Result = Collision::Sphere( m_Pos ); if( Result.m_Hit ) { // Cause damage to anything near us //... } break; } AI_EXPLODE Let’s define some states Simple AI
12
AI_EXPLODE m_HP = 0 Let’s define some states // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; } Simple AI
13
Let’s put it all together Simple AI AI_IDLE AI_SPAWN AI_ATTACK AI_EXPLODE m_HP = 0 See the player Near the player
14
void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } case AI_EXPLODE: { // Cause damage to anything near us… } // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; } Let’s put it all together Simple AI
15
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
16
Process your AI in parallel Threading AI AI State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding void UpdateAI( void ) { for( int i = 0; i < g_Num_AI; i++ ) { g_AI_Array[ i ].Update(); }
17
AI State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding Use data decomposition Threading AI State Machine Collision Pathfinding State Machine Collision Pathfinding Divide the AIs into groups. This is data decomposition. void UpdateAI( void ) { for( int i = 0; i < g_Num_AI; i++ ) { g_AI_Array[ i ].Update(); }
18
AI State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding Threading AI State Machine Collision Pathfinding State Machine Collision Pathfinding Divide the AIs into groups. This is data decomposition. void UpdateAI( void ) { for( int i = 0; i < g_Num_AI; i++ ) { g_AI_Array[ i ].Update(); } Use data decomposition
19
AI Threading AI Divide the AIs into groups. This is data decomposition. Submit the AIs to a job queue or use threading API like OpenMP or Intel® Threading Building Blocks. void UpdateAI( void ) { #pragma omp parallel for for( int Index = 0; Index < g_Num_AI; Index++ ) { g_AI_Array[ Index ].Update(); } Use data decomposition State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding
20
AI Threading AI class ParallelAIContext { void operator()( const tbb::blocked_range &range ) { for(int i = range.begin(); i != range.end(); ++i) { g_AI_Array [ i ].Update(); } void UpdateAI( void ) { tbb::parallel_for( tbb::blocked_range (0, g_Num_AI), *pParallelAIContext ); } Use data decomposition Divide the AIs into groups. This is data decomposition. Submit the AIs to a job queue or use threading API like OpenMP or Intel® Threading Building Blocks. State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding State Machine Collision Pathfinding
21
There might be dragons Threading AI void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } case AI_EXPLODE: { // Cause damage to anything near us… } // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; }
22
void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } case AI_EXPLODE: { // Cause damage to anything near us… } // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; } There might be dragons What if the collision system is accessed by multiple threads? Threading AI
23
void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } case AI_EXPLODE: { // Cause damage to anything near us… } // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; } What if multiple threads are running Move? There might be dragons Threading AI
24
There might be dragons void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player EnterCriticalSection( &critical_section ); Move( Path ); LeaveCriticalSection( &critical_section ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } break; } case AI_EXPLODE: { // Cause damage to anything near us //... } //... } We could add a critical section. But this makes all AI in AI_ATTACK block on each other. Threading AI
25
Move Collision First one there wins Uses exact positions Path data is read/write First one there wins Uses positions from last frame Path data is read only, update at end of frame Processed in order Cache data Environment is read/write Serial Parallel Processed out of order Use data from last frame Environment is read only Threading AI Clearly define interactions
26
Move Collision First one there wins Uses exact positions Path data is read/write First one there wins Uses positions from last frame Path data is read only, update at end of frame Processed in order Cache data Environment is read/write Serial Parallel Processed out of order Use data from last frame Environment is read only Threading AI Clearly define interactions
27
Move Collision First one there wins Uses exact positions Path data is read/write First one there wins Uses positions from last frame Path data is read only, update at end of frame Processed in order Cache data Environment is read/write Serial Parallel Processed out of order Use data from last frame Environment is read only Threading AI Clearly define interactions
28
Let someone else worry about it! We used Havok Physics™ for Smoke to process all collisions and character movement and it’ll enforce good results. Move Collision First one there wins Uses exact positions Path data is read/write First one there wins Uses positions from last frame Path data is read only, update at end of frame Processed in order Cache data Environment is read/write Serial Parallel Processed out of order Use data from last frame Environment is read only Threading AI Clearly define interactions
29
Why deal with it? Move Collision AI If Move/Collision can update on last frame’s data… Threading AI
30
Why deal with it? Move Collision AI If Move/Collision can update on last frame’s data… Threading AI
31
Why deal with it? Move Collision AI If Move/Collision can update on last frame’s data… Threading AI
32
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
33
Getting a job in Multithread Land Multithread Land How do we get collisions running independent of AI? Issue early, use late Deferred requests Task stealing
34
void Ai::Update( void ) { switch( m_State ) { case AI_SPAWN: { // Initial Setup Setup(); m_State = AI_IDLE; break; } case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::RayCast( m_Pos, GetPlayerPos() ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } case AI_ATTACK: { // Find a path to the player Collision::Path Path = Collision::FindPath( m_Pos, GetPlayerPos() ); // Update our position to move towards the player Move( Path ); // Check if we are close to the player Vector Distance = GetPlayerPos() - m_Pos; if( Distance.Magnitude() < 1.0f ) { m_State = AI_EXPLODE; } case AI_EXPLODE: { // Cause damage to anything near us //... } // Check out hit points if( m_HitPoints == 0 ) { m_State = AI_EXPLODE; } Let’s look at collision Multithread Land
35
Issue early, use late void Ai::PreUpdate( void ) { switch( m_State ) { case AI_IDLE: { // Issue collision check m_Handle = Collision::RayCast( m_Pos, GetPlayerPos() ); break; } void Ai::Update( void ) { switch( m_State ) { case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::GetResult(m_Handle ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } // … } Block if results are not ready Multithread Land
36
Issue early, use late void UpdateAI( void ) { #pragma omp parallel for for( int Index = 0; Index < g_Num_AI; Index++ ) { g_AI_Array[ Index ].Update(); } Multithread Land
37
Issue early, use late void UpdateAI( void ) { // Process all PreUpdates #pragma omp parallel for for( int Index = 0; Index < g_Num_AI; Index++ ) { g_AI_Array[ Index ].PreUpdate(); } // Process all Updates #pragma omp parallel for for( int Index = 0; Index < g_Num_AI; Index++ ) { g_AI_Array[ Index ].Update(); } Multithread Land
38
Deferred requests void Ai::PreUpdate( void ) { switch( m_State ) { case AI_IDLE: { if( !m_Hande ) { // Issue collision check if none are pending m_Handle = Collision::RayCast( m_Pos, GetPlayerPos() ); } break; } void Ai::Update( void ) { switch( m_State ) { case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::GetResult(m_Handle ); if( Result && Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } // … } Don’t block if results are not ready… just wait until next frame Multithread Land
39
Task stealing void Ai::PreUpdate( void ) { switch( m_State ) { case AI_IDLE: { if( !m_Hande ) { // Issue collision check if none are pending m_Handle = Collision::RayCast( m_Pos, GetPlayerPos() ); } break; } void Ai::Update( void ) { switch( m_State ) { case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::GetResult(m_Handle ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } // … } If results are not ready, have this thread start processing collision request. Multithread Land
40
Task stealing void Ai::PreUpdate( void ) { switch( m_State ) { case AI_IDLE: { if( !m_Hande ) { // Issue collision check if none are pending m_Handle = Collision::RayCast( m_Pos, GetPlayerPos() ); } break; } void Ai::Update( void ) { switch( m_State ) { case AI_IDLE: { // Check is we can see the player Collision::Result Result = Collision::GetResult(m_Handle ); if( Result.m_Hit == GetPlayerID() ) { m_State = AI_ATTACK; } break; } // … } If results are not ready, have this thread start processing collision request. Multithread Land Optimizing Game Architectures with Intel Threading Building Blocks (Brad Werth) 4:30 PM – 5:30 PM in Room 2011, West Hall
41
Agenda Define a Simple AI Challenge Threading AI Working in a Multithread Land Smoke: Multithread Land Summary
42
Smoke is a Multithread Land! Smoke Framework built by Intel for N-threads Demo uses real game technologies: Havok, FMOD, Ogre3D, DX9, animation, AI, and procedural content Well partitioned and configurable
43
AI Graphics How is Smoke threaded? Framework Change Control Manager Physics Interfaces Managers Environment Platform... Scheduler Task Manager Job Pool Scheduler updates each system every frame Change Control Manager traffics changes between systems Interfaces define interaction Smoke
44
AI Graphics How is Smoke threaded? Framework Change Control Manager Physics Interfaces Managers Environment Platform... Scheduler Task Manager Job Pool Scheduler calls into each system to update Smoke
45
AI Graphics How is Smoke threaded? Framework Change Control Manager Physics Interfaces Managers Environment Platform... Scheduler Task Manager Job Pool Each system divides its work and adds jobs to the job pool The Scheduler creates one worker thread per core on the platform Smoke
46
AI Graphics How is Smoke threaded? Framework Change Control Manager Physics Interfaces Managers Environment Platform... Scheduler Task Manager Job Pool If a system makes a change that other systems need to know about, it posts that change to the Change Control Manager This allows systems to run independently Smoke
47
AI Graphics How is Smoke threaded? Framework Change Control Manager Physics Interfaces Managers Environment Platform... Scheduler Task Manager Job Pool When all the jobs are processed, the Change Control Manager distributes changes 1 2 Smoke
48
How does AI work in Smoke? AI Task Scene Object... Framework Scheduler Interfaces Object When it’s time to update the frame, the Schedule calls into the AI system and tells it to update Smoke
49
How does AI work in Smoke? AI Task Scene Object... Framework Scheduler Interfaces Object The task updates the scene by dividing all the AIs into job. These jobs are put into the job pool in the Scheduler and farmed out to worker threads. Smoke
50
How does AI work in Smoke? AI Scene Object... Framework Scheduler Interfaces Object Each Object is an AI Each AI type has a state machine Each AI can have one or more goals. Goals are shared functionality between AI types State Machine Goal... Task Smoke
51
AI How does AI work in Smoke? Object AI Objects post changes as needed. Physics wants to know about velocity changes. Graphics wants to know about position changes from Physics. State Machine Goal... Physics (Havok) Graphics (Ogre3D) Object Smoke
52
Summary Thread your AI with data decomposition To maximize AI you need to thread Design AI to work with “remote” system Download Smoke at Whatif.intel.com
53
Q/A Summary Does multithreaded AI imply non- deterministic AI? Can scripting support threaded AI? ???
54
For More Information http://www.intel.com/software/gdc Email: orion.r.granatir@intel.com See Intel at GDC: –Intel Booth at Expo, North Hall –Intel Interactive Lounge – West Hall 3 rd floor Take a collateral DVD –Here in the room! –Intel Booth or Interactive Lounge
55
Get the “Story Behind the Story” Investing in Talent and Technology See What’s New Developers Connecting with Intel Engineers Training the Next Generation Enhance Your Products and Your Business The gateway to Intel’s worldwide technology, engineering and go-to-market support for Visual Computing developers www.intel.com/software/visualadrenaline
56
Intel @ GDC Wednesday, March 25 –Intel’s New Graphics Performance Analyzers 2:30 PM – 3:30 PM in Room 3004, West Hall –Kaboom: Real-Time Multi-Threaded Fluid Simulation for Games 4:00 PM – 5:00 PM in Room 2011, West Hall
57
More Intel @ GDC Thursday, March 26 –Who Moved the Goalposts? The Rapidly Changing World of CPU’s and Optimization 1:30 PM – 2:30 PM in Room 2011, West Hall –Taming Your Game Production Demons: the Offset approach 3:00 PM – 4:00 PM in Room 2011, West Hall –Optimizing Game Architectures with Intel Threading Building Blocks 4:30 PM – 5:30 PM in Room 2011, West Hall
58
Last of Intel @ GDC Friday, March 27 –Procedural and Multi-Core Techniques to take Visuals to the Next Level 9:00 AM – 10:00 AM in Room 2010, West Hall –Rasterization on Larrabee: A First Look at the Larrabee New Instructions (LRBni) in Action 9:00 AM – 10:00 AM in Room 135, North Hall –SIMD Programming on Larrabee: A Second Look at the Larrabee New Instructions (LRBni) in Action 10:30 AM – 11:30 AM in Room 3002, West Hall
59
INFORMATION IN THIS DOCUMENT IS PROVIDED IN CONNECTION WITH INTEL® PRODUCTS. NO LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY INTELLECTUAL PROPERTY RIGHTS IS GRANTED BY THIS DOCUMENT. EXCEPT AS PROVIDED IN INTEL’S TERMS AND CONDITIONS OF SALE FOR SUCH PRODUCTS, INTEL ASSUMES NO LIABILITY WHATSOEVER, AND INTEL DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF INTEL® PRODUCTS INCLUDING LIABILITY OR WARRANTIES RELATING TO FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER INTELLECTUAL PROPERTY RIGHT. INTEL PRODUCTS ARE NOT INTENDED FOR USE IN MEDICAL, LIFE SAVING, OR LIFE SUSTAINING APPLICATIONS. Intel may make changes to specifications and product descriptions at any time, without notice. All products, dates, and figures specified are preliminary based on current expectations, and are subject to change without notice. Intel, processors, chipsets, and desktop boards may contain design defects or errors known as errata, which may cause the product to deviate from published specifications. Current characterized errata are available on request. Performance tests and ratings are measured using specific computer systems and/or components and reflect the approximate performance of Intel products as measured by those tests. Any difference in system hardware or software design or configuration may affect actual performance. Intel, Intel Inside, and the Intel logo are trademarks of Intel Corporation in the United States and other countries. *Other names and brands may be claimed as the property of others. Copyright © 2009 Intel Corporation. Legal Disclaimer
60
Risk Factors This presentation contains forward-looking statements. All statements made that are not historical facts are subject to a number of risks and uncertainties, and actual results may differ materially. Please refer to our most recent Earnings Release and our most recent Form 10-Q or 10-K filing available on our website for more information on the risk factors that could cause actual results to differ.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.