0
\$\begingroup\$

I've been reading up about entity component systems as a design pattern for an OpenGL engine. The style I'm trying to implement has entities only being integers, and components being long contiguous arrays of, for example glm::vec3 for a world-position component.

The entity integers then work as indices into those arrays. All of this described best by this post.

As I understand, the main benefits of an ECS would include:

  • Simplification and elimination of unnecessary dependencies and spaghetti code
  • Performance boost: contiguous component arrays translate into fewer cache misses and an overall de-bloating of complex inheritance

While I do agree with the first point, I don't understand how the second could be true.

On a regular draw call, you'd need almost always the majority of components. You need position, scale, rotate for loading a MVP matrix into the shaders. You need the mesh and textures for rendering itself. You even need details like light color or whether or not it casts shadows. Everything! This means that you will inevitably encounter cache misses in some form, since you can't fit your component arrays in cache.

Add to that the fact that since the entity integers are indices into the component arrays, all of the component arrays need to grow in size whenever you add an entity - independent of it's type. This means that adding 30 entities with no mesh will inevitable generate 30 empty mesh allocations that will never be used.

How would you implement such a system to truly minimize cache misses without incurring in unnecessary memory waste?

\$\endgroup\$
1
  • \$\begingroup\$ I personally think the "better performance" thing is a myth - you usually iterate more components at a time with no guarantee they are in same order(=cache misses). The e/c will most likely only help you not-to write some bizarre OO code, which would be probably very inefficient. \$\endgroup\$
    – wondra
    Feb 15, 2015 at 0:33

1 Answer 1

2
\$\begingroup\$

The benefit of organizing data in the fashion described (storing things that will be frequently used or accessed together next to each other in memory) is not zero cache misses. It is fewer cache misses. That's all.

You're not wrong: if you represent your entity as an index, and use that index to refer to separate arrays for each of position, texture coordinates, mesh or shader references, et cetera, then yes, that's not very cache-efficient at all.

Instead, don't break your entity down into such pointless granular components. If you need position/texture coordinate/resource references all at the same time when processing that component (such as during rendering) store them all in a single record:

struct RenderComponent {
  Vector3 position;
  Vector2 textureCoordinate;
  Texture * texture;
  Shader * shader;
};

Create a an array of that structure and use your entity index to refer to that.

Don't fall into the (unfortunately extremely common) trap of thinking that building a component-based entity system means breaking down everything into the smallest thing possible. You want to break things down into the smallest component such that a single component is still a useful thing on it's own.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .