Truly terrible rendering performance...

Started by
21 comments, last by Mace 18 years ago
Does anyone have a resource on how I would take all of these blocks and "batch" them so that there are fewer calls?

I'm confused, are the texture changes the problem, or the amount of drawsubsets? Or is that the same problem?

I think there is something that I am missing.
[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
Advertisement
your goal is to always push as many triangles to the graphics card with the least amount of stalls. This is usually accomplished by the following:

1) Have the minimal amount of set texture calls

2) Have the minimal amount of index/vertex changes


To do this you usually do the following:

1) group by texture, and render all the identically textured triangles after the settexture call. This way you only need one setTexture call before you render all your similarly textured triangles. Each time your use setTexture, the texture is uploaded to your graphics card, the less you do this, the better.

2) Render as many triangles in one batch as possible. Sending 12 triangles (a simple cube) over and over to the card will kill your performance. You card like to take the biggest possible bite at a time.


I notice the following code in your rendermodel method:
D3DMATERIAL9 m = mod.materials;
Do you really need to make a copy of the material? How about
D3DMATERIAL9& m = mod.materials;
instead?

Drawing huge amount of boxes can be done by batching or Geometry Instancing. First one can be done on every hardware, latter with recent hardware.

For batching, I'd suggest splitting your world into cells of some size and then create a buffer for the blocks inside that cell. Of course you need to group the block according to the materials. This method is lacking dynamics. If some block is changed someway you need to recreate the whole batch (rotating, moving , deleting, adding).

Geometry Instancing works pretty close to the basic "1 draw call per object" but it uses streams in order to accomplish the whole rendering task with 1 draw call. Practically first stream contains the object and the second stream matrices for each block to be rendered.

If you plan the block rendering part carefully, you can create an interface which is able to use Geometry Instancing if available and batching as a fall back method.

Regards
Quote:Original post by ktuluorion
Does anyone have a resource on how I would take all of these blocks and "batch" them so that there are fewer calls?

I'm confused, are the texture changes the problem, or the amount of drawsubsets? Or is that the same problem?

I think there is something that I am missing.


The amount of calls to the hardware in general is the problem. While some state changes are more expensive than others, it is still relatively expensive to call anything across the operating system rings.

I just offered one guy advice on a similar problem; see here. Even though it seems that the topic is about VB6, the advice applies to Direct3D in general.

Niko Suni

Quote:Original post by Anonymous Poster
2) Render as many triangles in one batch as possible. Sending 12 triangles (a simple cube) over and over to the card will kill your performance. You card like to take the biggest possible bite at a time.


Im pretty new to DX myself after moving over from GL.
What you described here is my next step in optimizations but im having a hard time finding any sourcecode for this to familiarize myself with DX.

Figuring out how to build one big buffer is not a problem.
However im not sure about the matrices (translation, rotation, scaling) of each cube (in this example) and how to send them along with the vertexbuffer.
Is there a similar buffer to store matrices for each object as well?
Sadly there is no trivial way of combining multiple transforms and single draw calls. There is a technique called "Geometry Instancing" that can achieve this, but it's fairly advanced and isn't available on all hardware - thus it doesn't make sense to be relying on it for such a basic feature [oh]

If your game level is static, then I would suggest pre-transforming each block to its correct position when you create your "super buffer" containing all geometry. That way you can despatch the entire level as a single draw call yet still have the view/proj matrices control the view of it (so it's not completely transformed).

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Quote:Original post by jollyjeffers
Sadly there is no trivial way of combining multiple transforms and single draw calls. There is a technique called "Geometry Instancing" that can achieve this, but it's fairly advanced and isn't available on all hardware - thus it doesn't make sense to be relying on it for such a basic feature [oh]

If your game level is static, then I would suggest pre-transforming each block to its correct position when you create your "super buffer" containing all geometry. That way you can despatch the entire level as a single draw call yet still have the view/proj matrices control the view of it (so it's not completely transformed).

hth
Jack


Hmmm, i would like my engine to be able to run on all computers so i will have to figure out something else (alternatively check and use geometry instancing if its available on the system and fall back on something else if not).

I get about 60 fps rendering 730 cubes with 2 random materials (sorted by material with minimal state changes) on a Radeon 9800 Pro, amd 3000+.
Sure i have an old card, but im pretty sure theres more to squeeze out of it.
I only set the vbuffer to use once, but the 730 calls to DrawPrimitives appears to be the big bottleneck here.

The cubes are nodes in a scenegraph with can be assigned custom transformations, rotations etc, so they cant be treated as static geometry.
So let me get this straight -- somehow I will create a vertex buffer that contains all of my cubes combined? What kind of calls would I use to get several cubes combined and transformed?

[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
Quote:Original post by ktuluorion
So let me get this straight -- somehow I will create a vertex buffer that contains all of my cubes combined? What kind of calls would I use to get several cubes combined and transformed?


Well with indexed triangle list it is pretty straight forward. Just check the amount of space you need for the cubes (indices and vertices) and the create the buffers of the calculated size.

Then comes a bit harder part. The vertices you store in the VB need to be in the world space. So you transform the positions (and normals) manually and store that data in the VB. For the indices, you have to take account that the locations of the vertices aren't the same, so you'll need to add a starting location of the vertex for every index.

Draw it on the paper and you'll see the logic. It is pretty simple. Then you can draw all the boxes with a single drawing call.

This topic is closed to new replies.

Advertisement