Jump to content
  • Advertisement
Sign in to follow this  
directNoob

Applying the propper funciton pointer at runtime? (Mathfunctions)

This topic is 4278 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi to all. A couple of time now, I tryed to imagine how to assign a specific function pointer to the propper function itself. Here is the problem: When my application starts, the program makes an enumeration of the graphics hardware and the CPU. An important property this enumeration should reveal are the instruction sets. For example: Imagine that I implemented several mathematical ingedients for spacial calculation, e.g. vector math for diverent instruction sets. This means, I have a dot product implemented with SSE 3DNow, MMX, SSE2 ... Now the app detected that the CPU can handle SSE 3dNow and what ever... But I want to assign the vector function(pointer) to the propper implementation. I want to use the best one I can get. In the example above, this would be SSE. So I want that every usage of a vector product or the dot product refering/pointing to the propper implementation. And this would be the SSE implementation. I haven´t worked with smart pointers, but I could imagine, that this could be a solution to my problem?!(I know, smart pointers are imprtant. I will fill this gap soon...) But please tell my what I can do to get rid of this problem! Thanks a lot Alex

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
you are in fact on the right track, check out the following pseudo code:



//FIXME: return type & params

void doStuffWithMMX() {
// ...
}

void doStuffWithSSE() {
// ...
}

void doStuffWithSSE2() {
// ...
}

void doStuffWith3Dnow() {
// ...
}

int main()
{
typedef void (*MY_FPTR) ();

MY_FPTR pointers[]={&doStuffWithMMX,&doStuffWithSSE,&doStuffWithSSE2,&doStuffWith3Dnow}; //this could actually be a std::map<std::string, MY_FTPR>, to support syntax along the lines of: pointers["HAVE_SSE2"](...);

//check for hardware support
//call appropriate function
}





BTW, see: http://www.newty.de/fpt/fpt.html

Share this post


Link to post
Share on other sites
Hi, thanks for the fast response!

I understand.

But haven´t I to call pointer[...] every time than?

I think of someting like a general Name for the funciton like:

float DotProduct( CVector* )



But the function DotProduct() is assigned to the right function,
e.g DotProductSSE().

Thanks
Alex

Share this post


Link to post
Share on other sites
The classic way of doing this goes like this:


class Math
{
static float (*Length)(const Vector3 &);
// pointers for other functions

// Default "fallback" implementations
struct MathStd
{
static float Length(const Vector3 &x) { /* C implementation */ }
};

// SSE Implementations
struct MathSSE
{
static float Length(const Vector3 &x) { /* SSE implementation */ }
};

// 3DNow implementations
struct Math3DNow
{
static float Length(const Vector3 &x) { /* 3DNow! implementation */ }
};

// Assign correct functions to the appripriate pointers
static void Initialize(void)
{
if (HAS_SSE)
{
Length = MathSSE::Length;
}
else if (HAS_3DNOW)
{
Length = MathStd::Length;
}
else
{
Length = Math3DNow::Length;
}
}
};




This way, you only need to call one method - Initialize - which will automatically set pointes based on the heuristic you like (you can even do a speed test to select fastest routine). This also leaves and option to use SSE/3DNow implementations directly (without need for the pointer) which may be even better since it allows for function inlining and various optimizations.
To use those functions, you can simply call Math::Length(x) etc.

Share this post


Link to post
Share on other sites
Any particular reason you can't (or don't want to) determine the function to use at compile-time, instead? :s (e.g. by using ifdefs and conditional compilation)

Share this post


Link to post
Share on other sites
Hi thanks.

@b2b3:
Thanks. This is exactly what I was talking about!!!
For an even good approach in fast math functions, this should fit my needs and whose of my application.

But one question comes up now.
b2b3, you are using static methods. Is is better to use static methods or singletons, for example. But I don´t know if a math singleton is the correct way...
No, static funcitons or a static classes sounds great.

@Zahlman:
Quote:
(e.g. by using ifdefs and conditional compilation)

Before the idea with the pointers I had half implemented it with ifdefs, but than
I thought, this looks bad and it feels bad. How can I say it,...
I mean, when you have something like function pointers, why don't use then.
And there is a point of performace considerations(in my opinion, maybe I'm wrong. Maybe ifdef are faster than I think). I mean, consider the following problem I had:
You got a program which executes 1000 dot products in a sequence. So than, is it smart to ask the same question 1000 times, namly:"What instruction set do I have to use?"
E.g.:
I think this is what you mean:

float CVector::DotProduct( CVector &vc ){
...
#ifdef _SSE
// do SSE stuff
#elif _SSE2
// do SSE2 stuff
#elif _another expression
//...
#endif
}






Is this what you mean?
I'm not a hardcore programming specialist, but in my eyes this looks much slower than the function pointer approach...
I mean, with the pointers you just have to ask your question once:"What instruction set so I have to use?" and this is in the initialize function b2b3 posted!

Greetings
Alex

#EDIT
Forget about the performance consideration. I don´t thought about the name "preprocessor directives" and the fact that the compiler is responsible for linking the propper functions. But the smartness point of criticism holds!!!
Maybe this is the reason why smart pointers are calles smart pointers?! ;)
#/EDIT

Share this post


Link to post
Share on other sites
The #ifdefs are so called pre-processor directives. This means that they will only be evaluated BEFORE the actual compilation of your program.

if you have the code:


#ifdef _SSE
// do SSE stuff
#elif _SSE2
// do SSE2 stuff
#elif _another expression
//...
#endif


if you set _SSE2 for example the only code that will get to the compiler is:

// do SSE2 stuff

The small problem with this is a program compiled with SSE2 set will not run on a non-SSE2 CPU since the other code hasn't made it into the binary.

Share this post


Link to post
Share on other sites
Quote:
The small problem with this is a program compiled with SSE2 set will not run on a non-SSE2 CPU since the other code hasn't made it into the binary.

@Wc-duck(nice name:D)
Ok, thanks for this information. I wans't aware of this fact.

Alex

Share this post


Link to post
Share on other sites
Quote:
Original post by directNoob
I mean, when you have something like function pointers, why don't use then.


Because it costs you an extra pointer dereference for every single math operation. If you're going to use special instruction sets for extra speed doing serious number crunching, it's an important performance consideration.

Ideally you'd have separately written versions of all your bigger calculations (using, for example, templates, which are infinitely less ugly than the preprocessor) and try to work from there.

If you don't care about the speed, you might as well go on using the plain FPU.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!