Jump to content
  • Advertisement
AxeGuywithanAxe

Cache Coherency and Object Update

Recommended Posts

As far as i'm aware, there are two major paradigms when it comes to game object / game component updating.

The first is updating each "entity" at a time, including it's components"

The second is updating all components of a specific type at once.

The first approach seems to be easier to code , especially when you take into account update dependencies (i.e parent update before child) , but seems to be less efficient in terms of cache coherency and etc.

The second approach seems to be complicated to design , but helps with cache coherency and general optimizations  i.e animating all skeletal meshes at once , performing all navigation queries , etc.

It seems that most game engines , like unreal, that were built a decade + ago have turned their old game object hierarchy into the first approach , but I wanted to ask, if you were creating a game engine today, which approach would you choose?

Share this post


Link to post
Share on other sites
Advertisement

Thank you for the response!

I've actually been thinking about the way i'd handle data layouts. Each component would have what I refer to as "BusData" , bus data contains all of the memory that would be required for updating the component , and each component class also has a class called "BusDataProcessor" , so a skeletal mesh would have SkeletalMeshBusData and SkeletalMeshBusDataProcessor. When an object wants to be updated, it allocates an instance of it's BusData , therefore removing the issue of " you never actually need to update all those components at once" . If there is an allocated BusData in the processor, it is because the component wants to be updated. 

My main issue with the ecs model is that it seems to make certain issues like interobject dependencies , function overloading , and things of that nature more complicated. I've tried to cope with that by doing dependencies on a system basis.I have a "SpatialComponent" base class, which contains a transform/bounds/etc. Examples of the classes that subclass from this are skeletalmeshcomponent, staticmeshcomponent, etc. I also have a movement component and an input component. If the entity is a player , the movement component is dependent on the input component, but if the player is an ai, the movement component is dependent on the aicomponent. I could make it so that the movement component system is dependent on the ai and input component, but you can see how it can become convoluted. 

Share this post


Link to post
Share on other sites
11 minutes ago, AxeGuywithanAxe said:

My main issue with the ecs model is that it seems to make certain issues like interobject dependencies , function overloading , and things of that nature more complicated.

That's because "ECS" is an overengineering trap. These issues are only as complicated as you choose to make them, and you choose to make them more complex by ascribing more magic and dogma to what an "ECS" is than you should. Even your described "bus data" paradigm strikes me as overengineered by virtue of focusing on a generic, one-size-fits-all solution to everything and then trying to cast specific problem scenarios into that mold.
 

 

11 minutes ago, AxeGuywithanAxe said:

I also have a movement component and an input component. If the entity is a player , the movement component is dependent on the input component, but if the player is an ai, the movement component is dependent on the aicomponent. I could make it so that the movement component system is dependent on the ai and input component, but you can see how it can become convoluted. 

But remove "component" from the names of all these interfaces. You are left with the same "convoluted dependency" problem. The issue here isn't the component approach, per se. It's just the same old API interface design problems re-made with different names. The ECS magic bullet has been billed so hard (incorrectly) as a solution to these problems, but it isn't at all. It's a solution to an entirely different problem that gone through some kind of collective-consciousness mutation. Just like scene graphs did, back in the day.

If your agent movement is currently depending on pulling data from either the input system or the AI system, depending on the state of the agent (player controlled versus AI controlled), perhaps the solution is to have something push the movement commands to the agent movement object through the unified single interface of that object. Thus reducing the double dependency by inverting the relationship.

Share this post


Link to post
Share on other sites

I guess maybe I should of focused on the ideology behind ecs than the ecs paradigm in general. The bus data approach helps in the sense that you only load and focus on the data that is required on updating, no cache misses, no etc. I read the gdc presentation in which insomniac increased the speed of their code through smd by just focusing on the simple data that is required for updating.

Even in a game object model , or game object with component, the movement of a character is dependent on input. In UE4 they have a "controller" which is ticked prior to the movement component , through a dependency graph, and pushes commands depending on input , either by the playercontroller or the aicontroller, to the movement component so no matter the paradigm , my ideology is still to push the commands instead of reading. To my point about the "movement component being dependent" it is dependent on the others in that it has to be updated after it's had it's commands pushed, or there will be one frame of latency. 

Share this post


Link to post
Share on other sites

Data access patterns in an ECS are highly unpredictable, since each entity can have different behaviors that require different data at different times. This is entirely at odds with data-oriented design. You'll go mad trying to reconcile the two.

Share this post


Link to post
Share on other sites
14 minutes ago, Zipster said:

Data access patterns in an ECS are highly unpredictable, since each entity can have different behaviors that require different data at different times. This is entirely at odds with data-oriented design. You'll go mad trying to reconcile the two.

I don't know if I necessarily agree. Systems would provide the same update logic that an entity would do, but across all components of the same type at once. So in a game object model, you'd have a SkeletalMeshComponent that does the animation processing in a tick function, in ECS you would have a SkeletalMeshComponentSystem which updates all animations at once , even across threads.

I think the data access patterns are quite explicit. That seems to be one of the biggest advantages over the game object model.

Share this post


Link to post
Share on other sites
56 minutes ago, Zipster said:

Data access patterns in an ECS are highly unpredictable, since each entity can have different behaviors that require different data at different times. This is entirely at odds with data-oriented design. You'll go mad trying to reconcile the two.

If you're doing ECS "properly" (if such a thing can be said to be possible, given the disagreement over what ECS actually means) then you aren't updating each entity every frame, because an "entity" is just a binding mechanism that identifies groups of components. The most common operation should be updating homogeneous lists of components all at once, with operations that touch multiple components being comparatively "rare." Actually accomplishing this can indeed be "maddening" if you aren't used to thinking in those terms and don't have gameplay that's well-suited to that kind of decomposition.

Of course, I would like to point out that you can use non-dogmatic, data-oriented "outboard composition" without locking yourself into dogmatic ECS...

Edited by Oberon_Command

Share this post


Link to post
Share on other sites
3 hours ago, Oberon_Command said:

If you're doing ECS "properly" (if such a thing can be said to be possible, given the disagreement over what ECS actually means) then you aren't updating each entity every frame, because an "entity" is just a binding mechanism that identifies groups of components. The most common operation should be updating homogeneous lists of components all at once, with operations that touch multiple components being comparatively "rare." Actually accomplishing this can indeed be "maddening" if you aren't used to thinking in those terms and don't have gameplay that's well-suited to that kind of decomposition.

Of course, I would like to point out that you can use non-dogmatic, data-oriented "outboard composition" without locking yourself into dogmatic ECS...

I feel like the only maddening aspect I have about is that I can't seem to find a way to maintain the required entity update order (i.e update parent before child) , that is easily achievable in a entity component model , In that method I would just have an entity put it's parent as it's dependencies , and the component's would put it's owning entity as a dependency, and it's done. With system wide updating, it seems impossible in my mind to maintain this. 

Share this post


Link to post
Share on other sites
23 minutes ago, AxeGuywithanAxe said:

I feel like the only maddening aspect I have about is that I can't seem to find a way to maintain the required entity update order (i.e update parent before child) , that is easily achievable in a entity component model , In that method I would just have an entity put it's parent as it's dependencies , and the component's would put it's owning entity as a dependency, and it's done. With system wide updating, it seems impossible in my mind to maintain this. 

My first question would be, why do you need parent before child updating at the component level in the first place? What's the use case for that? Remember, a "component" is ideally a bundle of state that, in the most common operation over that state, is contiguous in memory. Can you rethink your decomposition to avoid the issue?

My second question would be, why can't you just sort the component array to enforce the update order? Or partition it, then update the partition with parents before the partition before children?

Edited by Oberon_Command

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!