views:

483

answers:

8

Hi, I'm new to C++ and DirectX, I come from XNA. I have developed a game like Fly The Copter. What i've done is created a class named Wall. While the game is running I draw all the walls. In XNA I stored the walls in a ArrayList and in C++ I've used vector. In XNA the game just runs fast and in C++ really slow. Here's the C++ code:

void GameScreen::Update()
{
    //Update Walls
    int len = walls.size();
    for(int i = wallsPassed; i < len; i++)
    {
        walls.at(i).Update();
        if (walls.at(i).pos.x <= -40)
            wallsPassed += 2;
    }
}

void GameScreen::Draw()
{
    //Draw Walls
    int len = walls.size();
    for(int i = wallsPassed; i < len; i++)
    {
        if (walls.at(i).pos.x < 1280)
            walls.at(i).Draw();
        else
            break;
    }
}

In the Update method I decrease the X value by 4. In the Draw method I call sprite->Draw (Direct3DXSprite). That the only codes that runs in the game loop. I know this is a bad code, if you have an idea to improve it please help. Thanks and sorry about my english.

+6  A: 

Try replacing all occurrences of at() with the [] operator. For example:

 walls[i].Draw();

and then turn on all optimisations. Both [] and at() are function calls - to get the maximum performance you need to make sure that they are inlined, which is what upping the optimisation level will do.

You can also do some minimal caching of a wall object - for example:

 for(int i = wallsPassed; i < len; i++)
 {
    Wall & w = walls[i]; 
    w.Update();
    if (w.pos.x <= -40)
        wallsPassed += 2;
 }
anon
What's the main difference between `[]` and `at()`? EDIT: Oh, just found the answer: `at()` checks the boundaries.
dreamlax
There is no real difference, the [] operated is overloaded so its just shorthand. Additionally I downvoted because this kind of optimization () vs [] is trivial.
aramadia
There is a difference - at() does range checking, which takes time and is pointless if you don't need it. And the effect of inlining operator[] (or at(), come to that) can be very marked.
anon
aramadia: as dreamlax correctly added, `at()` is checked and `[]` isn't. Hence the optimisation may be far from trivial since you're avoiding a conditional on every array access. Upvoting.
Peter
But the effect of one or two inlined `[]` operations is going to be negligible compared to the actual drawing.
Thomas
My bad then. However I still maintain its a negligible performance hit. Ill remove the downvote.
aramadia
I've seen inlining get a 3x speed increase on vector access, you will need it.
jk
Replacing at to [] changed dramatically the performance, Thanks! BTW, what are the optimization flags?Thanks again :)
Adir
@Adir Depends on your compiler - for GCC use -02 for starters.
anon
@Neil Butterworth my compiler is Visual C++
Adir
@Adir Sorry, I don't use VC++ any more - but optimisation control should be available via your project options dialog(s).
anon
It should be noted that `[]` in XNA (.net) will do the same bounds checking as `.at()`, so I highly doubt that's the issue...
BlueRaja - Danny Pflughoeft
If your 3d app changed speed measurably after making this change then something else must have changed at the same time. I guarantee this was not the limiting factor in your code.
Alan
How did this stupid micro-optimisation tip get picked as the best answer? If you think your 3D card is going to be stalled from rendering millions of pixels while the CPU does a bound-checked array-lookup, you're mad. By your logic, any Java/C# app would be slow. I'd love if we could get the accepted answer on a negative vote-count ;)
John
+2  A: 

Try to narrow the cause of the performance problem (also termed profiling). I would try drawing only one object while continue updating all the objects. If its suddenly faster, then its a DirectX drawing problem.

Otherwise try drawing all the objects, but updating only one wall. If its faster then your update() function may be too expensive.

aramadia
A: 

Have you tried multiple buffers (a.k.a. Double Buffering) for the bitmaps?

The typical scenario is to draw in one buffer, then while the first buffer is copied to the screen, draw in a second buffer.

Another technique is to have a huge "logical" screen in memory. The portion draw in the physical display is a viewport or view into a small area in the logical screen. Moving the background (or screen) just requires a copy on the part of the graphics processor.

Thomas Matthews
A: 

You can aid batching of sprite draw calls. Presumably Your draw call calls your only instance of ID3DXSprite::Draw with the relevant parameters.

You can get much improved performance by doing a call to ID3DXSprite::Begin (with the D3DXSPRITE_SORT_TEXTURE flag set) and then calling ID3DXSprite::End when you've done all your rendering. ID3DXSprite will then sort all your sprite calls by texture to decrease the number of texture switches and batch the relevant calls together. This will improve performance massively.

Its difficult to say more, however, without seeing the internals of your Update and Draw calls. The above is only a guess ...

Goz
A: 

To draw every single wall with a different draw call is a bad idea. Try to batch the data into a single vertex buffer/index buffer and send them into a single draw. That's a more sane idea.

Anyway for getting an idea of WHY it goes slowly try with some CPU and GPU (PerfHud, Intel GPA, etc...) to know first of all WHAT's the bottleneck (if the CPU or the GPU). And then you can fight to alleviate the problem.

feal87
+1  A: 
  • How fast is 'fast'?
  • How slow is'really slow'?
  • How many sprites are you drawing?
  • How big is each one as an image file, and in pixels drawn on-screen?
  • How does performance scale (in XNA/C++) as you change the number of sprites drawn?
  • What difference do you get if you draw without updating, or vice versa
John
+1  A: 

Maybe you just have forgotten to turn on release mode :) I had some problems with it in the past - I thought my code was very slow because of debug mode. If it's not it, you can have a problem with rendering part, or with huge count of objects. The code you provided looks good...

chris
A: 

The lookups into your list of walls are unlikely to be the source of your slowdown. The cost of drawing objects in 3D will typically be the limiting factor.

The important parts are your draw code, the flags you used to create the DirectX device, and the flags you use to create your textures. My stab in the dark... check that you initialize the device as HAL (hardware 3d) rather than REF (software 3d).

Also, how many sprites are you drawing? Each draw call has a fair amount of overhead. If you make more than couple-hundred per frame, that will be your limiting factor.

Alan