• Welcome to Dark Bit Factory & Gravity.
 

Graphics in C++

Started by Stonemonkey, January 13, 2007

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

Jim

I think GDI's SetDIBitsToDevice is at least as quick as FB memcpying into a DirectX surface.  I'd have to try it to be sure though.  Never looked at GDI+ before.  How easy is it to move a 32bit window sized memory buffer into a window and have it displayed.

->Fryer.  Shame you're not using Visual Studio Express.  Now you could turn on SSE or SSE2 and get another 2-4x speed up :P  Which version of devc++ is it (which is what I meant to ask last time, doh!)

Jim
Challenge Trophies Won:

Stonemonkey

I'm using VC++ express now but it's slower for this than devc and for some reason much slower in release mode and I've tried with SSE/SSE2 on.
Anyway, I've also compared with using a bit of asm for the scanline loops which is a massive improvement but could there be any way to get the compiler to compete with this? I'm not wanting to get into fixed point with this btw.

Jim

How are you measuring the performance?

Jim
Challenge Trophies Won:

Jim

I've stuck it in vtune.  The piece the optimizer is having trouble with is this, especially the pixel munging.  Your assembler is much faster but it shouldn't be.  Otherwise, the optimizer is beating the other chunk of assembler easily.

"" "367" "                 d=float(x_start)-xx0;" "" ""
"" "368" "                 red=rr0+dred*d;" "" ""
"" "369" "                 gre=gg0+dgre*d;" "" ""
"" "370" "                 blu=bb0+dblu*d;" "" ""
"" "371" "                 while (pixel_address<=last_address){" "" ""
"" "372" "                     *pixel_address=((int)red<<16)|((int)gre<<8)|(int)blu;" "" ""
"" "373" "                     red+=dred;" "" ""
"" "374" "                     gre+=dgre;" "" ""
"" "375" "                     blu+=dblu;" "" ""
"" "376" "                     pixel_address+=1;" "" ""
"" "377" "                 }" "" ""


I get about 150ms for 1000 tris with assembler, and 450ms without, Release or Debug doesn't make any difference.
I'm timing it like this


unsigned long long thetime(void)
{
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
return li.QuadPart;
}

unsigned long long freq;

void inittime(void)
{
LARGE_INTEGER li;
QueryPerformanceFrequency(&li);
freq = li.QuadPart;
}

void do_graphics_stuff(...)
{
...
char tmp[256];
unsigned long long t = thetime();
...thing to time
sprintf(tmp, "%I64ums\n", ((thetime()-t)*1000)/freq);
OutputDebugString(tmp);
}



You need to call inittime() somewhere in WinMain first.  I'm not timing the flip, just the triangles.
OutputDebugString() writes its output into the debugger output window in VS Express.

Jim
Challenge Trophies Won:

Jim

Almost certainly to do with float->int rounding for red,gre,blu, which isn't in the asm version, and is inside this tight loop.  Need to look at that.  I know you don't want to, but I'd seriously consider fixed point for the colours, because of this.  Keep it in float and see what you can do.

Jim
Challenge Trophies Won:

taj

If you want I have a C routine that does float to int using asm. I have one for cl somewhere and I have a macro for gcc somehwre too. Let me know...
Challenge Trophies Won:

Jim

Here's what I've done.  I've got this rounding routine

static inline unsigned int myfrnd(float f)
{
static const double magic = 6755399441055744.0;
double d;
d = f + magic;
return *(unsigned int *)&d;
}

#define float_to_int(in) myfrnd(in)

And I've changed the pixel line to read

*pixel_address=(float_to_int(red)<<16)|(float_to_int(gre)<<8)|float_to_int(blu);

That's just as quick as the asm version.

The magic constant is 2^51+2^52.  Adding that to a double makes the lower 32bits of the mantissa of the double equal to the integer part of the fp number.

Jim
Challenge Trophies Won:

Stonemonkey

Cool, thanks Jim. I was just looking into doing it that way but it wasn't quite as neat as that.

Jim

#28
Sadly, that trick doesn't work with SSE2 enabled, so here's how to do it using SSE2 intrinsic functions

#include <intrin.h>
static inline unsigned int myfrnd(float f)
{
return _mm_cvt_ss2si(_mm_load_ss(&f));
}

mm_load_ss loads a float into an SSE register, and mm_cvt_ss2si converts the single precision float to a 32bit int.
I had to comment out 2 lines in the intrin.h that conflict with winnt.h (_interlockedbittestandset and _interlockedbittestandreset) to get it to work.  The great thing is that these macros work well with the optimiser, meaning this version is about 25% faster than the asm.

You can use the _M_IX86_FP to detect what mode it's building in

#if _M_IX86_FP == 0
//fpu used
#elif _M_IX86_FP == 1
//sse used
#elif _M_IX86_FP == 2
//sse2 used
#else
#error unknown fpu architecture
#endif


That way you can have different builds for different platforms.

Jim

Actually, this works in SSE mode too.  Both the instructions it generates are SSE not SSE2.
Challenge Trophies Won:

taj

Quote from: Jim on January 21, 2007
Here's what I've done.  I've got this rounding routine

static inline unsigned int myfrnd(float f)
{
static const double magic = 6755399441055744.0;
double d;
d = f + magic;
return *(unsigned int *)&d;
}

#define float_to_int(in) myfrnd(in)

And I've changed the pixel line to read

*pixel_address=(float_to_int(red)<<16)|(float_to_int(gre)<<8)|float_to_int(blu);

That's just as quick as the asm version.

The magic constant is 2^51+2^52.  Adding that to a double makes the lower 32bits of the mantissa of the double equal to the integer part of the fp number.

Jim



Karma++++++++
nothing else to say, except that goes on my list for best post of the year.
Challenge Trophies Won:

Shockwave

Jim, you are awesome.
Shockwave ^ Codigos
Challenge Trophies Won:

Rbz

Challenge Trophies Won:

Stonemonkey

Example of what I've got so far with a couple of 2d drawing functions, this works in both DevC and VC but there is some asm (sorry Jim) that can be used if it's in VC.

Shockwave

Mmm. wouldn't compile in dev..

Undefined reference to setDIbitstodevice @48..

I'm thinking that it can't initialise the direct x screen.. I need to install this. Thanks for posting though! I'll look forward to seeing it when I have my compiler set up!
Shockwave ^ Codigos
Challenge Trophies Won:

Stonemonkey

It's not direct x, did you create it as a windows application?

Shockwave

lol, no I will try that.
I created it as an empty project! Sorry.
Shockwave ^ Codigos
Challenge Trophies Won:

Shockwave

Mmm. Created a windows app, it's over my head at the moment, I'll have to come back to this when I know what I am doing as I don't even know where to insert the code :P

I'm sure it looks great  :)
Shockwave ^ Codigos
Challenge Trophies Won:

Stonemonkey

delete all the code from the project and paste mine in. It doesn't really look great though.

Shockwave

Thanks :)

Looks a lot better than my hello worlds!!
Shockwave ^ Codigos
Challenge Trophies Won:

Stonemonkey

There's a lot of that sort of thing I should look into, doubt i could manage hello world without looking it up.