Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm using XNA to test an image analysis algorithm for a robot. I made a simple 3D world that has a grass, a robot, and white lines (that are represent the course). The image analysis algorithm is a modification of the Hough line detection algorithm.

I have the game render 2 camera views to a render target in memory. One camera is a top down view of the robot going around the course, and the second camera is the view from the robot's perspective as it moves along. I take the rendertarget of the robot camera and convert it to a Color[,] so that I can do image analysis on it.

private Color[,] TextureTo2DArray(Texture2D texture, Color[] colors1D, Color[,]   colors2D)
    {
        texture.GetData(colors1D);
        for (int x = 0; x < texture.Width; x++)
        {
            for (int y = 0; y < texture.Height; y++)
            {
                colors2D[x, y] = colors1D[x + (y * texture.Width)];
            }
        }

        return colors2D;
    }

I want to overlay the results of the image analysis on the robot camera view. The first part of the image analysis is finding the white pixels. When I find the white pixels I create a bool[,] array showing which pixels were white and which were black. Then I want to convert it back into a texture so that I can overlay on the robot view.

When I try to create the new texture showing which ones pixels were white, then the game goes super slow (around 10 hz).

Can you give me some pointers as to what to do to make the game go faster. If I comment out this algorithm, then it goes back up to 60 hz.

private Texture2D GenerateTexturesFromBoolArray(bool[,] boolArray,Color[] colorMap, Texture2D textureToModify)
    {            
        for(int i =0;i < screenWidth;i++)
        {
            for(int j =0;j<screenHeight;j++)
            {           
                if (boolArray[i, j] == true)
                {
                    colorMap[i+(j*screenWidth)] = Color.Red;
                }
                else
                {
                    colorMap[i + (j * screenWidth)] = Color.Transparent;
                }                
           }
    }

        textureToModify.SetData<Color>(colorMap);

        return textureToModify;
    }

Each Time I run draw, I must set the texture to null, so that I can modify it.

 public override void Draw(GameTime gameTime)
    {
        Vector2 topRightVector = ((SimulationMain)Game).spriteRectangleManager.topRightVector;
        Vector2 scaleFactor = ((SimulationMain)Game).config.scaleFactorScreenSizeToWindow;

        this.spriteBatch.Begin(); // Start the 2D drawing 
        this.spriteBatch.Draw(this.textureFindWhite, topRightVector, null,
           Color.White, 0, Vector2.Zero, scaleFactor, SpriteEffects.None, 0);
        this.spriteBatch.End(); // Stop drawing. 

        GraphicsDevice.Textures[0] = null;
    }

Thanks for the help,

Anthony G.

share|improve this question
    
have you thought about using shaders to access the texture data? Using the CPU will almost always be slower. –  Stephan van den Heuvel Dec 11 '12 at 20:04
    
No. But I will now. :) –  Anthony Dec 11 '12 at 21:11
add comment

1 Answer

To know the exact problem you should use a profiler but I can make an educated guess that the performance penalty comes from the call to texture.GetData(colors1D); in TextureTo2DArray.

As usual the excellent Shawn Hargreaves has written something about this:

Normally, the CPU and GPU run in parallel. Framerate = max(CPU time, GPU time).

If your code causes a pipeline stall, however, the processors must take turns to run while the other one sits idle. Yikes! Now framerate = CPU time + GPU time. In other words, programs that stall can be both CPU and GPU bound at the same time.

The easiest way to cause a stall is to draw some graphics into a rendertarget, then GetData on the rendertarget texture to read the results back to the CPU. Think about what happens if you do this: Charles (the CPU) is processing your drawing calls. He has filled a piece of paper with instructions for his brother George (the GPU). Charles reaches an instruction that says "copy data from George back into this array". But the drawing instructions haven't actually been processed by George yet! Charles cannot just note down the GetData call on his piece of paper. The next instruction might use values from the array, so he needs that data right away. Charles has no option but to immediately hand the incomplete list of drawing instructions over to George, then wait around twiddling his thumbs in boredom until George has finished drawing everything, at which point Charles can resume processing the GetData instruction while George becomes idle.

One of the great successes of the Direct3D API is how it hides the asynchronous nature of GPU hardware. Many graphics programmers are writing parallel code without even realizing it! But as soon as you try to read data back from GPU to CPU, all this parallelism is lost

http://blogs.msdn.com/b/shawnhar/archive/2008/04/14/stalling-the-pipeline.aspx

So it is generally not advisable to pipe data from the GPU back to the CPU.

Another problem is that processing individual pixels on the CPU is expensive. All modern GPUs calculate thousands of pixels at the same time but using the CPU its back to 1, 2, or 4 pixels. Remember inspecting a 1920x1080 image will mean 2073600 series of operations.

Now I don't know what the underlying problem is you're trying to solve by rendering a texture and inspecting if pixels are white but you're probably better off using some other way of abstracting this problem.

share|improve this answer
    
ok. I'll trying thinking of another sudo make magic way of doing it and post my results when I figure it out. Thanks for the help. –  Anthony Dec 11 '12 at 21:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.