views:

2228

answers:

2

Background: I'm using the SlimDX C# wrapper for DirectX, and am drawing many 2D sprites using the Sprite class (traditionally from the Direct3DX extension in the underlying dlls). I'm drawing multiple hundreds of sprites to the screen at once, and the performance is awesome -- on my quad core, it's using something like 3-6% of the processor for my entire game, including logic for 10,000+ objects, ai routines on a second thread, etc, etc. So clearly the sprites are being drawing using full hardware acceleration, and everything is as it should be.

Issue: The problem comes when I start introducing calls to the Line class. As soon as I draw 4 lines (for a drag selection box), processor usage skyrockets to 13-19%. This is with only four lines!

Things I have tried:

  1. Turning line antialiasing off and on.
  2. Turning GLLines off and on.
  3. Manually calling the line.begin and line.end around my calls to draw.
  4. Omitting all calls to line.begin and line.end.
  5. Ensuring that my calls to line.draw are not inside a sprite.begin / sprite.end block.
  6. Calling line.draw inside a sprite.begin / sprite.end block.
  7. Rendering 4 lines, or rendering 300.
  8. Turning off all sprite and text rendering, and just leaving the line rendering for 4 lines (to see if this was some sort of mode-changing issue).
  9. Most combinations of the above.

In general, none of these had a significant impact on performance. #3 reduced processor usage by maybe 2%, but even then it's still 8% or more higher than it should be. The strangest thing is that #7 from above had absolutely zero impact on performance -- it was just as slow with 4 lines as it was with 300. The only thing that I can figure is that this is being run in software for some reason, and/or that it is causing the graphics card to continually switch back and forth between some sort of drawing modes.

Matrix Approach:

If anyone knows of any fix to the above issue, then I'd love to hear it!

But I'm under the assumption that this might just be an issue inside of directx in general, so I've been pursuing another route -- making my own sprite-based line. Essentially, I've got a 1px white image, and I'm using the diffuse color and transforms to draw the lines. This works, performance-wise -- drawing 300 of the "lines" like this puts me in the 3-6% processor utilization performance range that I'm looking for on my quad core.

I have two problems with my pixel-stretch line technique, which I'm hoping that someone more knowledgeable about transforms can help me with. Here's my current code for a horizontal line:

    public void DrawLineHorizontal( int X1, int X2, int Y, float HalfHeight, Color Color )
    {
        float width = ( X2 - X1 ) / 2.0f;
        Matrix m = Matrix.Transformation2D( new Vector2( X1 + width, Y ), 0f, new Vector2( width, HalfHeight ),
            Vector2.Zero, 0, Vector2.Zero );
        sprite.Transform = m;

        sprite.Draw( this.tx, Vector3.Zero, new Vector3( X1 + width, Y, 0 ), Color );
    }

This works, insofar as it draws lines of mostly the right size at mostly the right location on the screen. However, things appear shifted to the right, which is strange. I'm not quite sure if my matrix approach is right at all: I just want to scale a 1x1 sprite by some amount of pixels horizontally, and a different amount vertically. Then I need to be able to position them -- by the center point is fine, and I think that's what I'll have to do, but if I could position it by upper-left that would be even better. This seems like a simple problem, but my knowledge of matrices is pretty weak.

This would get purely-horizontal and purely-vertical lines working for me, which is most of the battle. I could live with just that, and use some other sort of graphic in locations which I am currently using angled lines. But it would be really nice if there was a way for me to draw lines that are angled using this stretched-pixel approach. In other words, draw a line from 1,1 to 7,19, for instance. With matrix rotation, etc, it seems like this is feasible, but I don't know where to even begin other than guessing and checking, which would take forever.

Any and all help is much appreciated!

+1  A: 

it sounds like a pipeline stall. You're switching some mode between rendering sprites and rendering lines, that forces the graphics card to empty its pipeline before starting with the new primitive.

Before you added the lines, were those sprites all you rendered, or were there other elements on-screen, using other modes already?

unwind
Everything else that I'm rendering is using the sprite class, but I'm using a variety of calls to Sprite.Draw and Font.DrawString (which takes a Sprite object).
x4000
I am using a lot of Sprite.Begin and Sprite.End to send isolated batches (which can be sorted by texture), though -- this helps in efficiency quite a lot. My calls to line are outside any of those blocks, which is what makes it surprise me that it would have an issue.
x4000
I just added "thing's I've tried #8" to try to test if this is a pipeline switching issue between my sprite calls and the line calls. No dice. Isn't that strange?
x4000
A: 

Okay, I've managed to get horizontal lines working after much experimentation. This works without the strange offsetting I was seeing before; the same principle will work for vertical lines as well. This has vastly better performance than the line class, so this is what I'll be using for horizontal and vertical lines. Here's the code:

    public void DrawLineHorizontal( int X1, int X2, int Y, float HalfHeight, Color Color )
    {
        float width = ( X2 - X1 );
        Matrix m = Matrix.Transformation2D( new Vector2( X1, Y - HalfHeight ), 0f, new Vector2( width, HalfHeight * 2 ),
            Vector2.Zero, 0, Vector2.Zero );
        sprite.Transform = m;

        sprite.Draw( this.tx, Vector3.Zero, new Vector3( X1, Y - HalfHeight, 0 ), Color );
    }

I'd like to have a version of this that would work for lines at angles, too (as mentioned above). Any suggestions for that?

x4000