2
votes

I'm working on a "falling sand" style of game.

I've tried many ways of drawing the sand to the screen, however, each way seems to produce some problem in one form or another.

List of things I've worked through:

  1. Drawing each pixel individually, one at a time from a pixel sized texture. Problem: Slowed down after about 100,000 pixels were changing per update.

  2. Drawing each pixel to one big texture2d, drawing the texture2d, then clearing the data. Problems: using texture.SetPixel() is very slow, and even with disposing the old texture, it would cause a small memory leak (about 30kb per second, which added up quick), even after calling dispose on the object. I simply could not figure out how to stop it. Overall, however, this has been the best method (so far). If there is a way to stop that leak, I'd like to hear it.

  3. Using Lockbits from bitmap. This worked wonderfully from the bitmaps perspective, but unfortunately, I still had to convert the bitmap back to a texture2d, which would cause the frame rate to drop to less than one. So, this has the potential to work very well, if I can find a way to draw the bitmap in xna without converting it (or something).

  4. Setting each pixel into a texture2d with set pixel, by replacing the 'old' position of pixels with transparent pixels, then setting the new position with the proper color. This doubled the number of pixel sets necessary to finish the job, and was much much slower than using number 2.

So, my question is, any better ideas? Or ideas on how to fix styles 2 or 3?

1
In response to #1: Did you try batching your draws, rather than one at a time?user155407
No I don't believe so, d'you have a link or explanation handy? (If you mean drawing similar textures together, yes that did help, but it wasn't great.)Colton
Well, an easy thing to try to begin with is simply use a SpriteBatch, and Draw each pixel with a destination rectangle of size 1, 1, and sample from a very small texture with the color you want. If that's still slow you can do all this manually and not use any textures whatsoever (should speed it up a little). This is potentially a lot of polygons though, but it's worth a shot.user155407
Just glancing at the overloads, I am not quite sure how to implement this without a texture... It will be a while before I get to try it out. Originally I would draw a 1x1 texture (only one instance of each different color based on an index), and draw similar pixels together. I don't quite remember how the performance worked out.Colton
You can't implement it without a texture, at least for SpriteBatch. You can do it manually WITHOUT SpriteBatch.user155407

1 Answers

1
votes

My immediate thought is that you are stalling the GPU pipeline. The GPU can have a pipeline that lags several frames behind the commands that you are issuing.

So if you issue a command to set data on a texture, and the GPU is currently using that texture to render an old frame, it must finish all of its rendering before it can accept the new texture data. So it waits, killing your performance.

The workaround for this might be to use several textures in a double- (or even triple- or quad-) buffer arrangement. Don't attempt to write to a texture that you have just used for rendering.

Also - you can write to textures from a thread other than your rendering thread. This might come in handy, particularly for clearing textures.

As you seem to have discovered, it's actually quicker to SetData in large chunks, rather than issue many, small SetData calls. Determining the ideal size for a "chunk" differs between GPUs - but it is a fair bit bigger than a single pixel.

Also, creating a texture is much slower than reusing one, in raw performance terms (if you ignore the pipeline effect I just described); so reuse that texture.

It's worth mentioning that a "pixel sprite" requires sending maybe 30 times as much data per-pixel to the GPU than a texture.

See also this answer, which has a few more details and some in-depth links if you want to go deeper.