performance comparison in custom c++ render system. calling render function for different classes
I have this library in which there is a general display list for elements of different types, for each loop of the system, this display list is rendered by calling a render() method on every object added to the list. now, the list can have elements of different classes, say A,B,C,D all of them have their particular void render();
i have found two working ways of doing this and would like to hear which method should be better for performance in speed terms (or if there is a better method different from the ones i'm evaluating please suggest it).
option 1: the easiest way, i have an int type variable on a superclass common to every one of the A,B,C..etc classes, which identifies the number for that class. so, when the display list is rendering, there is a big switc开发者_如何转开发h() {} asking the type and depending on the value of this variable, a casting occurs to the respective class in order to render it, something like:
case OBJ_A:
((ObjA*)obj)->render();
break;
that's because all the objects are added to the list as pointers to the superclass type.
option 2: using function pointers. (as explained in http://www.newty.de/fpt/functor.html). here we have a template functor class, that can receive as parameter any of the other classes and stores a pointer reference to the render function. so when looping through it, the functor class will do the casting... i don't know the implications of this at runtime.
Thanks for any help on this!.
Why not use virtual functions?
class Renderable {
public:
virtual void Render() = 0;
};
class ARenderable : public Renderable {
public:
virtual void Render() {
// implement this
}
}
class BRenderable : public Renderable {
public:
virtual void Render() {
// implement this
}
}
// .. and then keep a list of Renderable's and call Render() on all of them
std::vector<Renderable*> rr;
rr.push_back(new ARenderable());
rr.push_back(new BRenderable());
// (pseudocode)
for each .. Renderable * r
r->Render()
The runtime overhead in all three cases is similar - basically, virtual functions are function pointers, just very elegant ones ;-) Using this strategy to solve such problems is idiomatic in C++ and fundamental in object-oriented programming.
Though Alexander Gessler's proposal is good and 99.9% likely the best one (virtual function calls are by no means as evil as many people think, unless you do millions of them every frame), here is another one that you might possibly consider, depending on the situation:
Sort your objects into buckets, then render all objects A, then objects B, then objects C, and so on. This will have somewhat higher management overhead, but will have no branches or virtual calls, which will somewhat make up for the higher management cost.
However, more importantly, it will reduce the number of state changes (texture binds, vertex buffer binds) in between draw calls, resulting in better batching. Also, it may yield a higher cache hit ratio for textures and vertex data. As such, it may give a huge performance boost (though, if you have few state changes, it won't).
精彩评论