![]() |
| ARF project in Visual Studio |
It was determined from day 1 that significant effort should be spent at ensuring that ARF libraries are modular and only have clean 1-way dependencies between them and generally accessible only through opaque interfaces. There are many benefits to organizing an evolving codebase this way.
Having feature sets as pluggable modules mean that modules can be included and excluded as is appropriate for a particular project, or when old features are obsolete and replaced by new features. No code bloat. Development also becomes straightforward because new features become easier to integrate into the rest of the framework when the dependencies are few and only happen between modules. Writing scripting wrappers or self-contained unit tests for example for the various modules without polluting the rest of the codebase also becomes an easy thing compared to a monolithic framework. Even compilation can generally be faster simply because header dependencies and library linkages occur per module only.
ARF also exposes opaque interfaces in a module so changing the implementation without affecting application code becomes easy. Opaque interfaces also clearly differentiates to users between code that is relevant to the application and internal code. This might seem obvious but it's surprising how many professional 3D engines implement multi-platform code with a haphazard bunch of #ifdefs. It's really quite hard on the eyes.
For example in ARF, the renderer module currently has a DX9 implementation, but the DX11 implementation can simply be swapped in since it also derives from the same interface as the DX9 implementation. Of course, it's not possible to define an abstract interface that covers every functionality so DX11-only functionalities will be exposed in a separate DX11-ish interface should the application or other modules require it.
Using interfaces often imply some sort of overhead but the organizational benefits often outweigh it.
Another thing that is important when writing modules for ARF is that modules should support scalable multi-threading. This means that if the performance of a certain feature can theoretically benefit from multi-threading, then it must be implemented in such a way that performance should scale with the number of threads. Each feature must also allow the application the flexibility to decide how many and which threads to use. With new CPUs having an ever-increasing number of cores, the old paradigm of having 1 thread on rendering, another on physics and another on AI is fast becoming irrelevant.

No comments:
Post a Comment