DirectX 9 performance compare: Texture atlas vs draw texture one by one

Started by
5 comments, last by AlanWu 10 years, 3 months ago

A long time ago, I saw people said "Batching render can improve a lot of performance."

But I couldn't find a method to batch render with a lot of textures. But I found texture atlas, which is a trick that put all the textures into a big texture and put mapping data in a big vertex buffer. So now I can do batching render with a lot of textures. But I found that Microsoft said "

Keep the textures small. The smaller the textures are, the better chance they have of being maintained in the main CPU's secondary cache.

Do not change the textures on a per-primitive basis. Try to keep polygons grouped in order of the textures they use. " today.

Well, obviously, a texture atlas have a huge size.

Microsoft also said "To get the best rendering performance during execution, try to work with primitives in batches and keep the number of render-state changes as low as possible. For example, if you have an object with two textures, group the triangles that use the first texture and follow them with the necessary render state to change the texture. Then group all the triangles that use the second texture."

So does it mean that I should draw texture one by one rather than batching a texture atlas? Did anybody do any experiment about this?

Also, Nvidia said "

The most straightforward way to render, say, two textured quads is to bind the

texture of the first quad (i.e., call SetTexture()), draw the first quad (i.e., call
DrawPrimitive()), then bind the texture for the second quad (i.e., call
SetTexture() again), and finally draw the second quad (i.e., call
DrawPrimitive() again). This rendering technique requires two batches.
If the two textures are combined into a texture atlas, as shown in Figure 1, you no
longer need to call SetTexture() between drawing the two quads, and thus are
able to combine the two DrawPrimitive() calls into one. In other words,

reduce batch-count from two to one."

That is so confusing!!!

Help!

Thanks~~~

Reference: Microsoft: http://msdn.microsoft.com/en-us/library/windows/desktop/bb147263(v=vs.85).aspx

Nvidia: http://http.download.nvidia.com/developer/NVTextureSuite/Atlas_Tools/Texture_Atlas_Whitepaper.pdf

Advertisement

So, I think there are three pieces of advice here. They're all correct, and I'd apply them in the following order (highest priority first):

1. Reduce the number of batches (draw calls). Texture atlasing is a good way to achieve this.

2. Reduce the number of state changes.. Rendering your batches in a sensible order is a good way to achieve this, although the exact details can be very unclear. Think of each draw call as a tuple of blend state, shaders, textures, vertex buffers (there's more), imagine 100s of these in various combinations representing the draw calls you need to issue to draw a complex scene. If you render in a random order, then that's sub-optimal as you're going to be introducing unnecessary state changes. If you order, by, say, texture then you reduce the number of texture changes, but maybe you're best off ordering by shader instead, that'll reduce the shader switches, but increase texture changes. Basically, the optimal ordering is very variable, it probably depends on the hardware, it probably even varies as the makeup of your scene changes even on the same machine. All you can really do is try to order as sensibly as possible, when you setup a render state, render everything you can with it, beyond that it's kind of tricky to know which to prioritise, but if you order by texture, then that's probably an OK choice. If it's very important to you, then you could write a system that lets you easily reorder your draw calls and you can measure the impact - tbh though, unless it's necessary to squeeze every bit of performance, then this probably isn't too important.

3. Smaller textures fit in the texture cache better, so don't use unnecessarily large textures, and do use mipmapping.

All the advice sounds good, the only exception is the detail about making the textures smaller. In the context of Texture atlases, this is only really relevant if the number of draw calls or state changes will stay the same.

I remember reading somewhere that the CPU to GPU data transfer (for textures) has increased in bandwidth a lot over the years, which is why cards have been increasing in memory from 128meg to over 3gb now. However, the number of draw calls you can achieve in a single frame is still around the same, somewhere in the ten's of thousands?

However, if in doubt, profile it!

[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

Optimizing graphics is about balance, tradeoffs, and measurement of your specific application.

All of the advice is correct, and noone can tell you what is "optimal", because nothing is generally optimal, it depends on what else you also do.

It also depends on what specific hardware you run it on.

And what exactly you want to draw (outdoor 3d scene, a 2d tilemap, indoor 3d-scene, medical visualisation, space scene, etc...)

profiliing and experimentation will tell you what is right for your case.

Also don't forget that to actually get done, you have to limit how much you allow yourself to spend optimizing, because there really is no end to what you _could_ do...

Thank you guys.
I got it now. But I am still going to do some experiment about this. But I almost know the answer.
:) thank you very much!

Optimizing graphics is about balance, tradeoffs, and measurement of your specific application.

All of the advice is correct, and noone can tell you what is "optimal", because nothing is generally optimal, it depends on what else you also do.

It also depends on what specific hardware you run it on.

And what exactly you want to draw (outdoor 3d scene, a 2d tilemap, indoor 3d-scene, medical visualisation, space scene, etc...)

profiliing and experimentation will tell you what is right for your case.

Also don't forget that to actually get done, you have to limit how much you allow yourself to spend optimizing, because there really is no end to what you _could_ do...


Yeah. I like your last paragraph. Got it. Thanks

So, I think there are three pieces of advice here. They're all correct, and I'd apply them in the following order (highest priority first):

1. Reduce the number of batches (draw calls). Texture atlasing is a good way to achieve this.
2. Reduce the number of state changes.. Rendering your batches in a sensible order is a good way to achieve this, although the exact details can be very unclear. Think of each draw call as a tuple of blend state, shaders, textures, vertex buffers (there's more), imagine 100s of these in various combinations representing the draw calls you need to issue to draw a complex scene. If you render in a random order, then that's sub-optimal as you're going to be introducing unnecessary state changes. If you order, by, say, texture then you reduce the number of texture changes, but maybe you're best off ordering by shader instead, that'll reduce the shader switches, but increase texture changes. Basically, the optimal ordering is very variable, it probably depends on the hardware, it probably even varies as the makeup of your scene changes even on the same machine. All you can really do is try to order as sensibly as possible, when you setup a render state, render everything you can with it, beyond that it's kind of tricky to know which to prioritise, but if you order by texture, then that's probably an OK choice. If it's very important to you, then you could write a system that lets you easily reorder your draw calls and you can measure the impact - tbh though, unless it's necessary to squeeze every bit of performance, then this probably isn't too important.
3. Smaller textures fit in the texture cache better, so don't use unnecessarily large textures, and do use mipmapping.

It's a very long one. Thank you very much for helping me. Though I don't very understand a bit about what you said in number 2. But I will do some experiment and decide. Also, I just want to make my engine very very fast. It is just one of my goal. I will try to achieve this goal as possible as I can.

This topic is closed to new replies.

Advertisement