Gamasutra: The Art & Business of Making Gamesspacer
Book Excerpt: Game Engine Architecture
View All     RSS
November 20, 2017
arrowPress Releases
November 20, 2017
Games Press
View All     RSS






If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Book Excerpt: Game Engine Architecture


November 25, 2009 Article Start Previous Page 2 of 6 Next
 

14.6.2. Performance Constraints and Batched Updates

Most low-level engine systems have extremely stringent performance constraints. They operate on a large quantity of data, and they must do a large number of calculations every frame as quickly as possible. As a result, most engine systems benefit from batched updating. For example, it is usually far more efficient to update a large number of animations in one batch than it is to update each object's animation interleaved with other unrelated operations, such as collision detection, physical simulation, and rendering.

In most commercial game engines, each engine subsystem is updated directly or indirectly by the main game loop rather than being updated on a per-game object basis from within each object's Update() function. If a game object requires the services of a particular engine subsystem, it asks that subsystem to allocate some subsystem-specific state information on its behalf. For example, a game object that wishes to be rendered via a triangle mesh might request the rendering subsystem to allocate a mesh instance for its use. (A mesh instance represents a single instance of a triangle mesh -- it keeps track of the position, orientation, and scale of the instance in world space whether or not it is visible, per-instance material data, and any other per-instance information that may be relevant.) The rendering engine maintains a collection of mesh instances internally. It can manage the mesh instances however it sees fit in order to maximize its own runtime performance. The game object controls how it is rendered by manipulating the properties of the mesh instance object, but the game object does not control the rendering of the mesh instance directly. Instead, after all game objects have had a chance to update themselves, the rendering engine draws all visible mesh instances in one efficient batch update.

With batched updating, a particular game object's Update() function, such as that of our hypothetical tank object, might look more like this:

virtual void Tank::Update(float dt)
{
// Update the state of the tank itself.
MoveTank(dt);

DeflectTurret(dt);

FireIfNecessary();

// Control the properties of my various engine
// subsystem components, but do NOT update
// them here...
if (justExploded)
{
m_pAnimationComponent->PlayAnimation("explode");
}
if (isVisible)
{

m_pCollisionComponent->Activate();
m_pRenderingComponent->Show();
}
else
{

m_pCollisionComponent->Deactivate();
m_pRenderingComponent->Hide();
}
// etc.
}

The game loop then ends up looking more like this:

while (true)
{
PollJoypad();

float dt = g_gameClock.CalculateDeltaTime();

for (each gameObject)
{
gameObject.Update(dt);
}

g_animationEngine.Update(dt);

g_physicsEngine.Simulate(dt);

g_collisionEngine.DetectAndResolveCollisions(dt);

g_audioEngine.Update(dt);

g_renderingEngine.RenderFrameAndSwapBuffers();
}

Batched updating provides many performance benefits, including but not limited to:

  • Maximal cache coherency. Batched updating allows an engine subsystem to achieve maximum cache coherency because its per-object data is maintained internally and can be arranged in a single, contiguous region of RAM.
  • Minimal duplication of computations. Global calculations can be done once and reused for many game objects rather than being redone for each object.
  • Reduced reallocation of resources. Engine subsystems oft en need to allocate and manage memory and/or other resources during their updates. If the update of a particular subsystem is interleaved with those of other engine subsystems, these resources must be freed and reallocated for each game object that is processed. But if the updates are batched, the resources can be allocated once per frame and reused for all objects in the batch.
  • Efficient pipelining. Many engine subsystems perform a virtually identical set of calculations on each and every object in the game world. When updates are batched, new optimizations become possible, and specialized hardware resources can be leveraged. For example, the PLAYSTATION 3 provides a battery of high-speed microprocessors known as SPUs, each of which has its own private high-speed memory area. When processing a batch of animations, the pose of one character can be calculated while we simultaneously DMA the data for the next character into SPU memory. This kind of parallelism cannot be achieved when processing each object in isolation.

Performance benefits aren't the only reason to favor a batch updating approach. Some engine subsystems simply don't work at all when updated on a per-object basis. For example, if we are trying to resolve collisions within a system of multiple dynamic rigid bodies, a satisfactory solution cannot be found in general by considering each object in isolation. The interpenetrations between these objects must be resolved as a group, either via an iterative approach or by solving a linear system.


Article Start Previous Page 2 of 6 Next

Related Jobs

Titan IM
Titan IM — Port Stephens, New South Wales, Australia
[11.19.17]

Senior Game/Software Programmer
TheWaveVR
TheWaveVR — Austin, Texas, United States
[11.18.17]

SOFTWARE ENGINEER GENERALIST
TheWaveVR
TheWaveVR — Austin, Texas, United States
[11.18.17]

SERVER PLATFORM ENGINEER
2K
2K — Novato, California, United States
[11.17.17]

LEAD TOOLS AND PIPELINE ENGINEER





Loading Comments

loader image