Search this blog

05 June, 2008

Performance does not matter

Well, it's a lie, of course it does, don't flame. But it's not what you should care about in your game/rendering framework. Or better, it's not the first thing you should care about.
Most of the times I've seen slow code, was not due to incompetent programmers (well, MOST of the times) nor due to a too high-level or slow framework (well, again MOST of the times). It was simply because the programmers did not have enough time in the project to optimize it. It's that simple. They knew how to speed it up, they had it into their "to-do" lists, but those ideas simply were never implemented. The same could be said about rendering features.

That should let us think. We come from eras when programs were small and computers did not have much resources. We had to optimize everything, we did use C and assembly. Nowdays, computers are powerful and our codebases are huge. Huge! We need to shift away from the low-level, hand optimize everything mindset. Not because we don't care about performances, but because to care about them we need to be able to iterate faster, to be more productive in our work.
We are writing kinda optimized bad code. We need to write better code (i.e. have the time to test different algorithms and ideas) and then, eventually, dig into low-level optimizations where needed. And the key to do that, is through productivity.

How does my ideal rendering framework look like? Well I'm not too sure but I think it should be...

  • Simple. Don't really care about building a huge, high level system with a lot of rendering features. For me, even something that's based on a scenegraph, is kinda bloated. You don't need a graph for most rendering tasks.
  • Customizable (code-wise). It should be easy to write custom rendering pipelines. Don't try to make it a generic blackbox, it won't work. Custom code has to be written. Don't bloat. Don't overengineer. Things do change. Don't go too big.
  • Designed for fast iteration. Data driven? Yes, but without overengineering it. Again, don't think about a huge, generic system, driven by parameters. But we do like to have a generic parameter system, to be able to easily drive systems with data, reflect it, save it, etc. Live tweaking (i.e. parameters, data)? Nice. Hot swapping (objects, shaders, textures)? That would be great. Live coding? Well, now maybe I'm dreaming...
  • Designed to be optimizABLE. Don't pessimize prematurely (i.e. don't do stupid things, that could be avoided without wasting any additional time). Do mature optimizations (i.e. care about performance where it has an impact in the overall design, that means, have a design that is not memory unfriendly for example, and that is not thread unfriendly)
  • Designed avoid bugs, designed to catch bugs (runtime checks, automated testing). Bugs are waste of time.
  • Integrated with tools, and artist pipeline. Tweaks done in the engine should be reflected into artists DCC programs. Tweaks done in DCC programs should be reflected into the engine. Ideally, data should be unique, external stuff, that can be modified by different clients, and that is managed by tools, versioning it, and converting it.
Note: that is probably not too far away from worse-is-better, I've also found interesting the futurist programming manifesto.


Jones said...

Nice read. The renderer design your describing is strinkingly similar to the one I created during my master thesis. Have a look if you're interested:
It will be open-sourced once the code is mature enough.

Jones said...

Forgot to mention, the thesis itself is in english. The PDF is linked on the bottom of the page.

Nick said...

I totally agree with your sentiments, and nice link from the 90's - good philosophy there.

Another rule of thumb I like to keep in mind when building new code is "this code might ship." Although it is true that premature optimization can cause you to waste time on something that is ultimately insignificant, on a big project, the deadline, and dozens of show-stopping bugs might arrive before you can go back and fix something that you wrote knowing that it was the wrong thing while you did it. If you remember "this code might ship", it will help you put the "right" amount of effort into every line you write - you don't need to make a polished diamond, but it'll help you not ship crap, too :)

DEADC0DE said...

Mhm right even if I think that the best thing is to think that any code could be the final one, or even better, that every design could be.

In other words, we have to avoid the "prototry" design pattern.

Thinking about shipping is not enough, as if a feature is fine, you'll be generally more than happy to ship it even if it's implementation is really poor (and the concept that every feature should be finalled early is already captured by the scrum philosophy, see my later post, "Framerate does matter")

Nick said...

Yes, I think we are in agreement if I read your comment properly.

On your "Framerate matters" post, you say "always have a programs that compiles... always not only something that compiles, but that actually works too."

My least favourite thing in programming is to be chasing down a bug, and find it in someone else's code with a comment beside it like /// @TODO Do this properly

Actually, there's one worse thing, which is when I find a TODO that I personally forgot about.

To paraphrase Yoda, "There is only do, or don't do, there is no TODO".