0

I'm writing a Falling Sand Simulator and I'm trying to determine the best way to draw on the screen. I noticed Texture2D.SetData is pretty slow but Im not sure what is making it slow.

I trying to figure out a way to spend up draws.

Which case would be the fastest?

Case A (Currently, What I am doing):

Create a pixel array. Update it, then use the pixel array in the Texture2D.SetData Method

Case B:

Separate the pixel array and texture into small chucks. Each chuck could have its own pixel array and texture. When it's time to draw, only draw a chuck if something changed in that chuck last frame.

Case C (might not be possible):

Have one pixel array but two textures. One texture is called front buffer and the another called back buffer. When the program starts, set both textures with the pixel array. On every draw, run a thread to set the pixel array to the back buffer and when thread finishes, the main thread swaps the front buffer and back buffer textures. The sole idea is to stop the Texture2D.SetData Method from blocking the main thread.

3
  • FYI: You probably wouldn't need separate textures for case B, you can use the overload of SetData that accepts a Rect to specify which part of the texture to update Commented Jan 26, 2024 at 17:03
  • @UnholySheep Ohh! Thats good to know. During the draw, do you know if using that overload multiple times with small chucks of data would be cheaper than in one shot like Case A? I'm not sure if the bottleneck is the amount of data(pixel array) being transferred to the GPU or just the fact that the CPU is talking to the GPU (Just calling SetData()). Commented Jan 26, 2024 at 19:30
  • I did something very similar some time ago and I can guarantee that you definitely have to use chunks (for most texture sizes anyway) like you proposed in B. Even further, for each chunk, keep a 'dirty rectangle' struct, which shrinks in size when nothing changes inside a chunk and instantly increases in size when something changed. Then update the texture only with that rectangle. I did it with one big texture but I wasn't using Monogame back then. The devs of Noita have an awesome video about that very technique on Youtube. Commented Jan 27, 2024 at 1:19

1 Answer 1

0

Texture.SetData and then drawing that texture, is essentially doing all of the work on the cpu and none of it on the gpu. Also, each SetData call itself is immediately expensive and interrupts the rendering pipeline. The way to efficiently interleave changes to texture data into the render pipeline, is to allocate a RenderTarget and then issue draw calls to it.

The normal way to draw a 2D thing is SpriteBatch. The way to do whatever it is you are doing efficiently though, is going to 100% depend on the specifics like .. do you actually need/want 1x1 pixel resolution for whatever you are doing? Does the change need to happen immediately? Do you need cpu access to it? How many draw calls are needed to effect the changes for one frame on it? Does it need to persist at all as a RenderTarget or should this just be drawing to the backbuffer?

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.