Elvas Tower: Draw calls - Elvas Tower

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Draw calls Rate Topic: ***** 1 Votes

#1 User is offline   Genma Saotome 

  • Owner Emeritus and Admin
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • Group: ET Admin
  • Posts: 15,359
  • Joined: 11-January 04
  • Gender:Male
  • Location:United States
  • Simulator:Open Rails
  • Country:

Posted 16 November 2023 - 11:57 AM

When rendering, is an entire model sent to the GPU and the GPU does the draw calls by texture + material type or does OR send multiple batches from the model over to the GPU (as Draw Calls) that have been individually culled by the texture + material type requirement?

Is it different for terrain on account of the microtex file?

#2 User is offline   James Ross 

  • Open Rails Developer
  • Group: Status: Elite Member
  • Posts: 5,491
  • Joined: 30-June 10
  • Gender:Not Telling
  • Simulator:Open Rails
  • Country:

Posted 21 November 2023 - 03:38 PM

View PostGenma Saotome, on 16 November 2023 - 11:57 AM, said:

When rendering, is an entire model sent to the GPU and the GPU does the draw calls by texture + material type or does OR send multiple batches from the model over to the GPU (as Draw Calls) that have been individually culled by the texture + material type requirement?

The latter.

The process of loading a model looks something like this:

  • Send textures to GPU
  • Send vertex buffer (list of X/Y/Z coords) to GPU
  • Send index buffer (list of vertex indexes) to GPU
  • Send shaders to GPU

The process of rendering a model looks something like this:

  • Tell GPU which already-loaded textures to use
  • Tell GPU which already-loaded vertex buffers to use
  • Tell GPU which already-loaded index buffers to use
  • Tell GPU what rendering parameters to use (depth culling function, blend mode, etc.)
  • Tell GPU which shader to use (this also passes along all of the shader parameters)
  • Send draw command (which specified the range of items in the index buffer to use)

As such, the program (Open Rails here) is in charge of making sure the right data is set in the GPU just prior to each draw command. A very long time ago, Open Rails did not sort/group models by their texture/material (which includes the rendering parameters, shader, and shader parameters), setting them each time and causing the GPU to constantly keep jumping around. This was fixed to group by texture/material, so that the highly repetitive steps are reduced.

I don't believe we sort/group by the vertex or index buffers, as they're not shared normally IIRC.

For instancing, there's an additional instance buffer which is processed the same as the index buffer.

View PostGenma Saotome, on 16 November 2023 - 11:57 AM, said:

Is it different for terrain on account of the microtex file?

Open Rails considers the terrain texture + microtex texture as a single material IIRC, so it will only be grouped if both textures are the same file.

#3 User is offline   Genma Saotome 

  • Owner Emeritus and Admin
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • Group: ET Admin
  • Posts: 15,359
  • Joined: 11-January 04
  • Gender:Male
  • Location:United States
  • Simulator:Open Rails
  • Country:

Posted 22 November 2023 - 12:33 PM

View PostJames Ross, on 21 November 2023 - 03:38 PM, said:


Open Rails considers the terrain texture + microtex texture as a single material IIRC, so it will only be grouped if both textures are the same file.


Thank you for the full explanation.

Followup questions for terrain (just to be sure I really understand): I think what you are saying is when a tile has several textures applied to the tile you process all of the patches with the same surface texture so it's 1 draw call per unique texture, n calls for the patch, right?

Second question: You mentioned not "sorting the vertex or index buffers, as they're not shared normally". I've often wondered how professional game studios merge several textures to a face -- think repeating stone path pattern across a town square, grime/dirt pattern 1, grime/dirt pattern 2 at a different scaling, random bits of greenery pattern such that in the end there is no longer a visible repeating pattern of any of the art because none of the tiling edges of one texture line up with the others and the art of each, in total, obscures the tiling edges of all. Is the answer found in the concept you mentioned OR doesn't do?

#4 User is offline   James Ross 

  • Open Rails Developer
  • Group: Status: Elite Member
  • Posts: 5,491
  • Joined: 30-June 10
  • Gender:Not Telling
  • Simulator:Open Rails
  • Country:

Posted 22 November 2023 - 05:30 PM

View PostGenma Saotome, on 22 November 2023 - 12:33 PM, said:

Followup questions for terrain (just to be sure I really understand): I think what you are saying is when a tile has several textures applied to the tile you process all of the patches with the same surface texture so it's 1 draw call per unique texture, n calls for the patch, right?

It's always 1 draw call per patch, but they're grouped by texture/material so that it's more efficient (for both CPU and GPU) by not constantly switching textures.

There's a little extra optimisation for terrain with no holes (i.e. no tunnel portals): they all share the same index buffer, which is only set once.

View PostGenma Saotome, on 22 November 2023 - 12:33 PM, said:

Second question: You mentioned not "sorting the vertex or index buffers, as they're not shared normally". I've often wondered how professional game studios merge several textures to a face -- think repeating stone path pattern across a town square, grime/dirt pattern 1, grime/dirt pattern 2 at a different scaling, random bits of greenery pattern such that in the end there is no longer a visible repeating pattern of any of the art because none of the tiling edges of one texture line up with the others and the art of each, in total, obscures the tiling edges of all. Is the answer found in the concept you mentioned OR doesn't do?

There are multiple ways you can apply textures to a surface like this and I have not looked at what the professional games do.

But I suspect the most efficient way is to pass all the textures into the shader (i.e. base texture + all overlays, although that may in fact be just one texture for everything anyway!) and have it compute everything in a single pass. You can provide the shader with any number of texture coordinates for each vertex, as well as arbitrary data, so you could pass in just the right coordinates to do it, or a texture index and coords. This is nothing more than a generalised version of microtex (i.e. a slightly more advanced shader).

I believe that the MSTS shape file format can support this in theory, but I am not sure any of the shaders in MSTS allowed it nor do the Open Rails shaders (outside of the special terrain shader).

I would expect glTF to support this, but I am not sure if our glTF patch includes it.

#5 User is offline   Genma Saotome 

  • Owner Emeritus and Admin
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • Group: ET Admin
  • Posts: 15,359
  • Joined: 11-January 04
  • Gender:Male
  • Location:United States
  • Simulator:Open Rails
  • Country:

Posted 22 November 2023 - 09:02 PM

View PostJames Ross, on 22 November 2023 - 05:30 PM, said:

It's always 1 draw call per patch, but they're grouped by texture/material so that it's more efficient (for both CPU and GPU) by not constantly switching textures.


So it's always 64 calls per near terrain tile. Hmmm. That is a lot when you have 10km of near terrain in sight and there is DM on top of that. Might it be worthwhile for the loader to provide an ordered list of the patches in an information list, something like this:
  • TextureFileName1: patch 1, 2, 3....44;
  • TextureFileName2: patch 45, 46, 50, 52;
  • TextureFileName3: patch 47, 48, 49, 51, 53...64;


so, given this example, would only 3 calls be needed? If something like that is possible it could save a lot processing power and give us higher fps. No need for that in MSTS when all you could ever see was 9 tiles but OR is a completely different beast.

View PostJames Ross, on 22 November 2023 - 05:30 PM, said:

There are multiple ways you can apply textures to a surface like this and I have not looked at what the professional games do.

But I suspect the most efficient way is to pass all the textures into the shader (i.e. base texture + all overlays, although that may in fact be just one texture for everything anyway!) and have it compute everything in a single pass. You can provide the shader with any number of texture coordinates for each vertex, as well as arbitrary data, so you could pass in just the right coordinates to do it, or a texture index and coords. This is nothing more than a generalised version of microtex (i.e. a slightly more advanced shader).

I believe that the MSTS shape file format can support this in theory, but I am not sure any of the shaders in MSTS allowed it nor do the Open Rails shaders (outside of the special terrain shader).

I would expect glTF to support this, but I am not sure if our glTF patch includes it.


That is very interesting James. My own need in this regard is large buildings, 50, 100m plus in one direction or another. Repeating patterns in the art for walls are generally handled by the pretense of windows and the architectural decisions of the building structure that produce long, narrow faces. It is the wide open face seen in roofs that really need combining textures. But that is my own corner case... I think its plausible that improvement in the appearance of road and track could be obtained by the same idea of using a smaller, sharper texture as the base texture, say concrete, and several differently scaled grunge textures merged in.

Stick the idea on near the end of the list, who lknows, maybe sometime it'll manage to get to the top.

#6 User is offline   gpz 

  • Superintendant
  • Group: Status: Elite Member
  • Posts: 1,772
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 23 November 2023 - 12:06 AM

View PostJames Ross, on 22 November 2023 - 05:30 PM, said:

But I suspect the most efficient way is to pass all the textures into the shader (i.e. base texture + all overlays, although that may in fact be just one texture for everything anyway!) and have it compute everything in a single pass. You can provide the shader with any number of texture coordinates for each vertex, as well as arbitrary data, so you could pass in just the right coordinates to do it, or a texture index and coords. This is nothing more than a generalised version of microtex (i.e. a slightly more advanced shader).

I believe that the MSTS shape file format can support this in theory, but I am not sure any of the shaders in MSTS allowed it nor do the Open Rails shaders (outside of the special terrain shader).

I would expect glTF to support this, but I am not sure if our glTF patch includes it.

The patch supports everything that is in the core glTF specification, and some extensions too. (Exception is the draco mesh compression.) James described the process well: pass all the textures and draw everything in one pass. Different textures may have different coordinates, so the base texture may be tiled, while e.g. the roughness texture not, making all the tiled parts look a bit differently. This is all supported in the patch as it is part of the core glTF.

#7 User is offline   James Ross 

  • Open Rails Developer
  • Group: Status: Elite Member
  • Posts: 5,491
  • Joined: 30-June 10
  • Gender:Not Telling
  • Simulator:Open Rails
  • Country:

Posted 23 November 2023 - 05:05 AM

View PostGenma Saotome, on 22 November 2023 - 09:02 PM, said:

So it's always 64 calls per near terrain tile. Hmmm. That is a lot when you have 10km of near terrain in sight and there is DM on top of that.

It looks like it from quickly reading the code, but it's been ages since I actually worked on it, so it might not be so. If you'd like to confirm anything about the rendering there are two things you can use in-game:

The DEBUG HUD lists out the number of primatives of each type (13 currently) as you probably remember.

The other is command Debug Log Render Frame (Alt + F12), which dumps an entire frame into the log broken down by all the relevant things. Each "{...}" block represents one of the primative types above, plus shadow maps and DM. Each line with a number at the start represents a group of draw calls which share the same material, shown after the number.

Here's an example from the distant mountain section in my standard test route (MSTS's Isaburo activity, at the start):

    WorldOpaque {
      13    * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oerotgenscrub3.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      11    * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oerotgenscrub2.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      9     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oerotgenscrub4.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      8     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oerotgenscrub5.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      3     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\forest.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      6     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oerotgenscrub1.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      1     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oegenfield2.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      1     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oegenfield1.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
      2     * TerrainSharedDistantMountain(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\oegenfield3.ace~c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\terrtex\microtex.ace)
    }

You can see from this that there are 9 different materials (for terrain that only means texture combinations), and a total of 54 draw calls.

      12    * SceneryMaterial(c:\users\james\programs\microsoft games\train simulator testing\routes\japan2\textures\road.ace:00000001:0)

For scenery materials, instead of a second texture, there are the material options which include shader, lighting, and texture options. The final number is the mip-map bias.

Even though we'll only load a given texture once, if you use it with different material options we have to rendering using multiple groups.

View PostGenma Saotome, on 22 November 2023 - 09:02 PM, said:

Might it be worthwhile for the loader to provide an ordered list of the patches in an information list, something like this:
  • TextureFileName1: patch 1, 2, 3....44;
  • TextureFileName2: patch 45, 46, 50, 52;
  • TextureFileName3: patch 47, 48, 49, 51, 53...64;


so, given this example, would only 3 calls be needed? If something like that is possible it could save a lot processing power and give us higher fps. No need for that in MSTS when all you could ever see was 9 tiles but OR is a completely different beast.

I think it should be possible to organise the buffers such that it was less draw calls. The terrain is static, after all, which means we only need to figure this stuff out while it loads.

#8 User is offline   Genma Saotome 

  • Owner Emeritus and Admin
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • Group: ET Admin
  • Posts: 15,359
  • Joined: 11-January 04
  • Gender:Male
  • Location:United States
  • Simulator:Open Rails
  • Country:

Posted 23 November 2023 - 12:59 PM

View PostJames Ross, on 23 November 2023 - 05:05 AM, said:


I think it should be possible to organise the buffers such that it was less draw calls. The terrain is static, after all, which means we only need to figure this stuff out while it loads.

Collecting the information should be simple. I hope using it won't be terribly hard to implement.

Thanks for the other information, I will use it to increase my understanding the price of my modeling. Adding it to the manual (and much of what you've written here) could be useful for other content creators.

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users