Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design  (Read 11594 times)

0 Members and 2 Guests are viewing this topic.

Xornand

  • Jr. Member
  • **
  • Posts: 78
  • C++ / Python
    • View Profile
Thought it would be interesting to those who still haven't seen it. The video comes from the last CppCon and it's about Data Oriented Design. The speaker talks about what he thinks is wrong with the mainstream approach to programming - and especially in the case of C++, he discourages the use of templates, exceptions and STL altogether.

He's also against design patterns and the impression is that he's not too fond of the entire OOP too, as it focuses on writing the code which is based around idealized models of the world, as opposed to the actual, "real" data. Apparently, it is very important to have as little L1 and L2 cache misses as possible in triple-A game engines, and the mainstream approach to programming doesn't really care much about it.


Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #1 on: October 15, 2014, 05:29:43 pm »
Really interesting talk, I liked to see a view that's quite different from the general opinion. Mike Acton is right in saying that a lot of code doesn't care about efficient use of caches, and that the typical OOP approach doesn't encourage such code.

But I also disagree in several places, and partly I have the impression that he is very focused in his particular environment where fully exploiting the available performance is crucial. This is well visible when somebody states that there are cases where engineers' time is the critical resource and not performance, thus it pays off to use abstraction in order to develop faster. Mike doesn't have a convincing answer.

Another point is that he advises against templates, exceptions and STL but mentions no alternative. Faced with the question how he deals with code duplication without templates, he mentions external code generators -- I wonder if they really use that, i.e. have to run an external tool every time they need a container of different types? Also, the main argument against templates was the compile time -- something which is only apparent for complex metaprogramming like in Boost libraries, and can also be partly mitigated using precompiled headers. It's also interesting because most of the other anti-OOP advocates (Alexander Stepanov foremost) are big fans of templates and the way implicit polymorphism works.

What hasn't convinced me either is that data-oriented design would generally increase maintainability and debugability -- after all, a lot of abstraction mechanisms exist for the sole purpose of making data more understandable and intuitive to humans. Ironcially he shows an example of processing an array of scene nodes by getting a char* pointer to a member, reinterpret-casting it to the value and moving the pointer forward by sizeof(type) ;)

Data-driven programming is often represented as an opposite of OOP, but I don't think that's completely true. I wonder whether it would be possible to come up with idioms (as part of C++, or even features in other languages) that allow to make use of some convenient features like genericity or encapsulation despite working directly with data. The examples from the talk require a lot of manual interaction, are not reusable and not maintainable -- I don't believe this must be an inherent property of such designs.

To sum up, I think he makes some really good points about data-oriented design, but the applicability remains within a small domain; a combination with other designs is not considered.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Strelok

  • Full Member
  • ***
  • Posts: 139
    • View Profile
    • GitHub
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #2 on: October 15, 2014, 05:58:09 pm »
All this talk about performance is wholeheartedly agreeable until you check their latest game which will run at piss poor 30fps. So much time spent optimizing code when the end user experience will be suboptimal anyway. I wonder how badly a normal c++ engine would fare on a "next gen" console.

Mörkö

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #3 on: October 16, 2014, 03:47:41 pm »
Mike Acton is for sure a better software engineer than I will ever be, but despite that I still prefer the Unix style in favor of Actons incredibly clever data driven optimization.

Quote
Rule of Clarity: Clarity is better than cleverness.

Because maintenance is so important and so expensive, write programs as if the most important communication they do is not to the computer that executes them but to the human beings who will read and maintain the source code in the future (including yourself).

In the Unix tradition, the implications of this advice go beyond just commenting your code. Good Unix practice also embraces choosing your algorithms and implementations for future maintainability. Buying a small increase in performance with a large increase in the complexity and obscurity of your technique is a bad trade — not merely because complex code is more likely to harbor bugs, but also because complex code will be harder to read for future maintainers.

Code that is graceful and clear, on the other hand, is less likely to break — and more likely to be instantly comprehended by the next person to have to change it. This is important, especially when that next person might be yourself some years down the road.
Emphasis mine.
« Last Edit: October 16, 2014, 03:49:20 pm by Mörkö »

Strelok

  • Full Member
  • ***
  • Posts: 139
    • View Profile
    • GitHub
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #4 on: October 16, 2014, 05:07:11 pm »
write programs as if the most important communication they do is not to the computer that executes them but to the human beings who will read and maintain the source code
That is true for huge open source projects that don't have definite resource costraints. As Mike says, (when it comes to performance and USER EXPERIENCE) the code is just a tool.
Buying a small increase in performance with a large increase in the complexity and obscurity of your technique is a bad trade
Although we're not talking about "small increase in performance" but (ms to ns) I have to agree with you. I don't see how overcomplicating everything to have the most performance will help in most common cases, unless your team is made of 5+ assembly gurus, that is. Of course when you have to work with an nvidia G70 with GPU clock 550MHz and 256MB of GDDR3 RAM and 256MB xRAM you will need to squeeze out everything you can get.

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #5 on: October 17, 2014, 04:45:13 pm »
The talk is quite interesting, and he does hit a few points right. However, I agree with Nexus. He is too involved with his own environment that he simply can't explain objectively what he means to.

He swallows his own words most of the time and complicates the idea he wants to pass on, but in the end, its all about shifting our code towards efficient cache use, as well as writing code that is favorable to memory access patterns on modern machines.

From what I can see, there are two main things he advocates:

1) Whenever possible, put your data in sequential chunks for faster processing, as pulling/pushing data from memory is one of the most expensive things you can do in realtime applications; Even when this implies sacrificing something else, its worth it because cache efficiency is the most powerful optimization you can do.

2) Be careful with how you access your data, to avoid for example, load-hit-store hangs; So, be careful how we read and write to our variables etc.

I just think he is too extreme about it and became a fanboy of himself, as this kind of design is not antagonistic to other design patterns or OOP.

--

In the end, if you are developing a game, you should just think what entities you have and how they relate to each other. Then apply these principles where it makes sense to.

Let me try to give a nice example. Imagine you are making a nice shmup with potentially hundreds or thousands of bullets in the screen at once; let's take the bullets as a prime example for data oriented design. They will all be moving every frame, usually very fast, so we know we will have a lot of bullets, and they all have movement in common. We know allocation is an expensive operation, especially if its happening every frame hundreds of times, so we automatically know we need a pool for optimal usage; we preallocate a ton of bullets using a std::vector<Bullet> (for example) and can almost assume we will never need another allocation for bullets.

Now, we know that every frame we can just iterate a cache efficient structure to update the bullet transforms with an efficient calculation. This is pretty much the most efficient way to go about bullet processing. But, the key here is that laying our data in such arrays of structures is NOT antagonistic to having our GameObjects and typical OOP hierarchies.

One of the most beautiful ways to go about using both approaches together (in my opinion) is to use "deferred data" in our classes. This means essentially that our classes still can access the data exactly like the old days, completely internally, but the data is not allocated there anymore, but rather in an external block of memory. Instead, a pointer or handle is used to access it every time it is needed.

Using the above example, we already solved efficient iteration and behavior updating of our bullets in a good way. Now, let's say each of our bullet-shooting GameObjects wants to render bullets in different ways, there is no need to pollute the Bullet class with all this rendering data with various types etc. We simply keep track of the handles to the right bullets in our classes, and use their data to render the bullets however we want to.

To make sure our simple integer handles stay valid, depending on the nature of our pool container etc, we can use "roster" systems, an additional array of indices that remaps our handles to the actual indices of the real pool. Since many pools like to have "alive" instances together for even quicker iteration, this means handles would break often, but not with our roster system, which would ensure valid handles. There are many ways to go about this, but I do believe this is the core of what data oriented design is. Sorry for the wall of text.

 

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #6 on: October 21, 2014, 01:55:58 pm »
That Data Oriented Design reduces cache misses is a nice sideeffect, and sure people advocating it always include telling about it, because it really is nice.
Then people hear that and think "Ahh, its only about optimizing cache misses, I dont need that, therefore its wasting programmer time". The real point they are missing is that it helps if you dont need to look at  dozens of layers of trees of overengineered classes (http://en.wikipedia.org/wiki/Lasagna_code) every time you need to find out whats really going on. Instead, if you have the data directly inside several homogenous arrays, a number of simple to understand loops directly operating on it is all thats needed.

For the bullet example, instead of packing everything into one class, it might be better to split it up and have, for example, an array of positions, another with its velocity and other physical data, and shared data for the visual appearance.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #7 on: October 21, 2014, 02:14:45 pm »
Overengineered classes are always unfortunate, but that's not a problem inherent to OOP, but a result of bad design. There are enough places where abstraction is really needed, and in those situations data-driven design doesn't magically improve things. Either you store the data representation in a cache-friendly place and reference it from a different (more logical and intuitive) place*, or you just ditch the whole abstraction and start duplicating code.

And I don't see how separate arrays for positions, velocities, forces and other attributes are simpler or more intuitive than an array of bullets. A lot of things are more complicated because you need to keep the elements of different arrays synchronous, e.g. for removal, sorting, etc. C++ idioms like remove-if cannot be easily performed across different containers. If you introduce a new attribute, you have to adapt dozens of places that manipulate the element order to take into account that new array, whereas with one bullet array, you do absolutely nothing. As soon as refactorings are due, lack of encapsulation is yet another factor in exploding development time.

______
* That's what Grimshaw meant with "deferred data"; to me, it looks like a really good way of taking the best of both worlds.
« Last Edit: October 21, 2014, 02:16:37 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #8 on: October 21, 2014, 02:22:13 pm »
It can be simpler to have a structure of arrays instead of an array of classes, because it eliminates the need for that class to access many different systems. Then you are able to keep the physics code for bullets and other things together somewhere and the rendering code together somewhere, without it being intermingled by having bullet code together, code for other single real world object together.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #9 on: October 21, 2014, 02:43:07 pm »
Theories are nice, but you only understand the pros and cons with an actual implementation. Not that I would understand things better, it's more that in theory things can always look so easy.
All the discussion around "it might be ... if ... and ..." are useless if you don't get around to implement anything in either system due to being stuck with theoretical architectures. ;D

Data-driven designs are nothing really new and as wintertime kind of hinted at, they can be used easier in combination with Component Based designs. Just Google for both terms and you'll find quite a few relations.

I haven't found the time/motivation to watch the talk yet, but it sounds like Mike Acton is going into one direction too extremely. C++ is a multi-paradigm language on purpose, sticking to just one "pattern" is never a really good idea and one should not forget that it's always a question of balance, you can't have all of the three worlds:



I'm not sure what he says in the video, but from the discussion here, it seems as if everyone forgot that games are only 50% CPU based. A lot of the crucial optimization also needs to happen on the GPU end and especially between the CPU and GPU. So while you can optimize things as much as you want for CPU usage, it won't magically serve your GPU's needs.
« Last Edit: October 21, 2014, 02:56:02 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

MorleyDev

  • Full Member
  • ***
  • Posts: 219
  • "It is not enough for code to work."
    • View Profile
    • http://www.morleydev.co.uk/
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #10 on: October 21, 2014, 09:28:23 pm »
it eliminates the need for that class to access many different systems. Then you are able to keep the physics code for bullets and other things together somewhere and the rendering code together somewhere, without it being intermingled by having bullet code together, code for other single real world object together.

That sounds like exactly what you get with clean OO designs? Like, that's how I'd expect an OO system to look: A place for everything and everything in it's place.

People seem to get way too hung up on the extreme/worst examples "Object Orientated", "Functional" or "Data-Driven" when most applications have to deal with multiple interacting requirements that often are each best suited to different approaches. So which of those approaches should you use? Yes, yes you should.

In the end, all of these approaches exist to solve problems in specific contexts, context matters and often one approach is well suited for one area of the code but isn't for another. Has "Mix-and-match programming" been coined yet? :)
« Last Edit: October 21, 2014, 09:43:25 pm by MorleyDev »
UnitTest11 - A unit testing library in C++ written to take advantage of C++11.

All code is guilty until proven innocent, unworthy until tested, and pointless without singular and well-defined purpose.

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #11 on: October 22, 2014, 01:25:43 am »
I second what MorleyDev says. I proudly mix all kinds of patterns and "architectures" in my code. Whatever fits my current sense of elegance and performance is what finds its way into the source, even if it has to be refactored later.

I really advocate iterating a lot while writing code, especially if its going to be a library API or something similar. I despise implementing everything and cluttering the API from the start as it's almost always wasted time (partially at least) and since API's take time to develop and become mature, its really good to keep iterating and using it during that time. Trial by fire to your own code, allowing it to fail early and achieve a nice tradeoff of all worlds, as exploiter's post mentions.

Other than that, my opinion is: don't try to optimize every single thing for cache efficiency right away. Do what works and use these techniques where its absolutely obvious you should do it. This is because many times you make a nice contigous container and yet the nature of the task doesn't allow you to iterate it sequentially at all. In this case you're not really squeezing lots of extra performance and the design got complicated anyway, uselessly.

Syntactic Fructose

  • Jr. Member
  • **
  • Posts: 80
  • Overflowing stacks and eating snacks
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #12 on: October 22, 2014, 09:19:15 am »
I was lucky enough to see this conference in person, awesome talk!

Mörkö

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Insomniac Game Engine Developer Shares Some Thoughts On Engine Design
« Reply #13 on: October 22, 2014, 10:37:49 pm »
Chandler Carruth of Google gave a talk on a similar topic. I thought his approach was more reasonable than Mike Acton.



The short version is: "Forget about the other containers, just use vector."

 

anything