Skip to main content
GameDev.net gamedev.net
🔒 Locked

Passing variable argument types

Started by ZealousEngine Jul 23, 2007 at 5:07 PM 15 replies 2.1k views
Original Post
ZealousEngine
ZealousEngine
I have a active object that includes all the 'rendering' for my game. When I want to 'do something' graphical, I write a little function, then send a callback request to this graphics active object. All callback requests sent to the active object go into a little queue, and are processed fifo style, on the active objects own thread. The problem is, how can you store all these functors/callbacks in the queue? I mean, it works great when were just calling nullary functions (they can all fit in one list), but what about a callback that needs some kind of argument (of X type)? So, my question is, how can I pass arguments (of all diferent types) to this active object, have the arguments buffered somewhere, then passed along to the function? Thanks for any insight *keep in mind performance is a huge concern. I did find a solution using boost bind, but it was far to slow to bind every callback request at runtime.
ZealousEngine
ZealousEngine
No ideas?

Best I could think of would be to leave the callbacks all as nullary functions (no arguments). Now they all fit in the 'queue list', and can be processed first in first out. To pass arguments to these functions/callbacks, you could write a special 'argument transporter' function for each argument type (just a simple buffer to store floats, ints, ect.. then read them back fifo once the callback is called).

So something like this...

Quote:

graphics->callback( &someFunction );
graphics->passArgument( someArgument );
graphics->passArgument( anotherArgument );

...

void someFunction( void ) {

float arg1 = graphics->getNextFloatArgument();
int arg2 = graphics->getNextIntArgument();

//do stuff with the two arguments

}


Not the most elegant solution, but it 'works'. If you have a better idea im dien to hear it :0
Valere
Valere
This sounds like the Command Pattern to me. Instead of passing a callback function, pass a functor (a function object).

There are many more advanced (and correct) ways to do this, but this class sketch should give you the idea. boost::function is one library that can help out, but I understand that it has performance issues.

class IRenderCommand{public:     void Execute() { ExecuteInternal(); };private:     virtual void ExecuteInternal()=0;};class ConcreteRenderCommand:   public IRenderCommand{public:      Matrix transform;      Image  texture;private:      void ExecuteInternal()       {              //Guts of the operation here      }};
Antheus
Antheus
Quote:
*keep in mind performance is a huge concern. I did find a solution using boost bind, but it was far to slow to bind every callback request at runtime.


This is probably as fast as it gets ( see the referenced article as well). This approach eliminates the penalty of boost's functions and memory allocations it performs.
ZealousEngine
ZealousEngine
There are two problems with boost::function and boost::bind.

For one, how can I maintain a list/queue of boost::functions if they are all different (ie you cant put a nullary function and a function that takes a int argument in the same list).

And two, binding the function at runtime is INSANELY slow. For example, if you wanted to update the position of the camera every frame, its 100x faster to use my method (using a 'preset' binding/callback, and just passing the argument seperately). So I need to setup all my functors/callbacks in the init step, then never touch them again.
Antheus
Antheus
Yes, dynamic binding and other dynamic approaches are "slow". If they are performance issue, you're almost certainly abusing them.

If you're calling these dynamic functions from inside the render loop, that's almost certainly an incredible performance hit that nothing will solve.

Other option is of course virtual functions, and defining callbacks as interfaces. That'll be as fast as it gets for such generic approach.
ZealousEngine
ZealousEngine
Hmm that article on delegates looks interesting (never heard of em before). It looks like just a 'faster' way to use boost::function? I dont see how it solves the problems I listed above though (I missed something I guess?).

@Antheus

The problem is, I dont want to have to hard code a complex interface in my graphics active object. I want to 'hook on' generic callbacks, and pass arbitrary argument types. There has to be a elegant AND performance friendly way...
Valere
Valere
Whoops, I guess I skimmed past the bits where you mentioned considering functors already. Now that I look at it, I'm not sure If I can help you with a simple fast and elegant solution to this one.

If you can modify the called function signatures, you could make it a little less ugly by creating a RenderArgs class that handles the "GetIntArg" "GetFloatArg" stuff in your earlier solution to not clutter up the graphics class with that functionality and pass a render args with your function pointer (and recieve it in the function signature).

And Getting into Conjecture of Ideas outside my realm of immediate experience:

If you use bind (or an equivalent) and you fill in concrete arguments, doesn't it return a nullary functor, that you can call later? If these have the same type (and I think they do) you could store lists of them. That would solve half the problem, wouldn't it?

A quick test in my compiler reveals this to be legal:

void CBoostBindTest::Test(){boost::function<void ()> f1 = boost::bind(&CBoostBindTest::Test2, this, 1);}void CBoostBindTest::Test2(int iTest){}


So you could just make sure that you call all of your arguments concretely when you bind.

Or is this the solution you already arrived at using bind?
ZealousEngine
ZealousEngine
Well, you CAN do the following...

Quote:


std::vector< boost::function > callbackQue;

callbackQue.push_back( boost::bind( &someFunction, someFloat, someInt ) );



The problem is, hard binding the arguments like that is INSANELY slow for some reason. Its MUCH faster to just bind a nullary function during app init, and pass the arguments via some other method.

What exactly did you mean by using a "RenderArgs" class? You mean something like boost::any? Wouldnt that cause performance issues?
ZealousEngine
ZealousEngine
Do you mean setup all my callback functions like...

Quote:


void someFunction( ArgList args ) {

//extract arguments form 'args'

};



Im not sure how to write a container class like that (one that can take varying argument types)
Valere
Valere
Im having fun trying to tackle this problem, so I apologize if this is pretty scatter shot. I can only think of a few ways to do this. The requirement of arbitrary function signatures is what makes this hard to in c++.

Really Ugly:

If the callee knows the args it expects, you could store things as void*, and cast them to what you need. Since this is an asynchronous, these would be pointers to copies of the original args passed in, and would need to be deleted when the arg list is cleaned up. So much for type safety :) You could implement some ad-hoc type safety by storing void* paired with the type obtained from RTTI, but that's rather slow.

Really Slow:

Use boost::any.

---

To revist my earlier command pattern suggestion, how difficult of a requirement would it be to require the creation of a function wrapper class for each function you want to be able to pass into the renderer?

If they all have a common interface that reduces to the nullary function, store the arguments (strongly typed) and know how to call the function pointer (or fastest possible delgate) that they hold, then the renderer can hold lists of these and call them in a queue order. For a small amount of class overhead, you'd gain a lot of safety and speed.

You could probably even write a set of template classes that inherit from the common interface to allow you to write these automatically.

Non-templated example:
class ConcreteRenderCommand3 : public IRenderCommand{public:   ConcreteRenderCommand3(SomeFunctionPointer pFunc, Type1 Arg1, Type2 2Arg2, Tyep3 Arg3){/*member assignment*/};private:   void ExecuteInternal()   {       pFunc(Arg1,Arg2,Arg2);   };//member declarations here};


Then your source would just call:
pRenderer->AddCommand(new ConcreteRenderCommand3(&function, a1,a2,a3)); 


Should be type-safe, and very fast with free functions.
ZealousEngine
ZealousEngine
Well void* are too ugly, and boost::any is way too slow.

Im a little confused about your function wrapper class idea. It seems like that would require writing a special class for EVERY possible combination of arguments I might need to send (one for int float, one for float float, ect...). It seems like it would be less work (although maybe not as clean) to just use my original 'argument transporter functions'? Or did I miss something?
ZealousEngine
ZealousEngine
Well lets say I did create a special class/function for each possible argument list, so something like...

Quote:

void Graphics::addCommand( funcPtr ) {
//add a nullary function to the que
}

void Graphics::addCommand( funcPtr, int ) {
//add a function with a single int argument to ANOTHER que (wont fit in the same one).
//and manage the storage/passing of the int in this specific function
}


I think that would work, but the problem is, how can I make sure these commands are processed fifo? I mean, I cant store a nullary command and the int command in the same list, so when the Graphics active object is processing all these commands, how will it maintain fifo order? *EDIT wait a minute, I think I see what you were getting at earlier. If these classes are sub classes of a base 'command' class, I should be able to squeze them all into a single queue...

Also, is there anyway to take advantage of templates to reduce the amount of code im going to have to write?
Valere
Valere
Sorry for taking a couple days out here.

Sure, first, set an arbitrary number of arguments as the max you can ever accept. Let's say 8. So, write 9 templated functions, one for each overload. Here's the one for one argument. (Note, I'm pretty sure this won't work as-is. I just sketched this out without ever looking at a compiler or a reference)

class Renderer{  //  // ...  //  template <class FuncSig, class Arg1Type>  void addCommand( FuncSig funcPtr, Arg1Type a1)   {    IRenderCommand* pCommand = new RenderCommand1<FuncSig, Arg1Type>(funcPtr, a1);    m_Queue.Add(pCommand);//Must cleanup command later  }  //  ...};


I don't think raw function signatures can have their type deduced, so users of this function would have to explicitly provide it as the first template argument.

You have to do roughly the same thing with the RenderCommand class. Create 9 of them (one for each number of args you want to support).

template <class FuncSig, class Arg1Type>class RenderCommand1 : public IRenderCommand{public:    RenderCommand1(FuncSig pFunc, Arg1Type a1) : m_pFunc(pFunc), m_a1(a1) {};private:    Arg1Type m_a1;    FuncSig  m_pFunc;    void ExecuteInternal()    {         pFunc(m_a1);    };};


So all you should have to do in your render loop is call something like the following since your templated subclass takes care of the details of calling the function pointer.
    IRenderCommand* pCommand = m_Queue.front();    pCommand->Execute();    m_Queue.pop();    //clean up pCommand memory here


Best to test performance out on this sort of solution with the one argument case before going nuts. I really don't have the knowledge to say how fast it might be. You could probably get away with only doing the one (and 0) argument cases, and just ask clients to provide a single struct to the render command.
ZealousEngine
ZealousEngine
Awesome that looks perfect!

My only concern would be, for high frequency commands (like setting the position of the camera), do you think having to new and delete for EVERY command is going to cause any performance issues? I wonder if there is a way to preallocate and reuse buffers for the argument/command storage...
ZealousEngine
ZealousEngine
And one other quick question -

Were not actually dealing with function pointers, but member function pointers. Which requires you store a pointer to the object AND the function (right?)? However, im a little fuzzy on how you combine the two (the object pointer AND the member function pointer), and how you 'call it'. It seems really easy with regular function pointers ( since the () operator is recognized ), is it just as easy with member functions?

*nm I guess this is just the basic concept of a functor. Something I never had to deal with since boost::bind shielded me fromt he details. I think I can figure this part out.

I am still curious if there is a way to preallocate buffers for these commands/arguments so I wont be calling new/delete a million times per loop... or should I not even be worried about that kind of overhead?

[Edited by - ZealousEngine on July 26, 2007 4:45:25 PM]
ZealousEngine
ZealousEngine
OK, what im gonna try and do is create a 'Command Manager' class. Anytime you want to create a new command, instead of just 'newing' a new object, you REQUEST a new command pointer from the command manager. This way the command manager can recycle old commands (aka areas of memory) so we dont have to new and delete constantly.

Think it will work (or more importantly, think the extra overhead will still result in a net performance increase?)?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.