<p>This started out as a comment and became to long so I am posting it as an answer.</p>
<p>Regarding what to measure: Usually measuring how many milliseconds a particular step takes not only gives decent performance information, it can help narrow in on the exact area that is taking up the most time.  FPS can be computed from average frame time. Individual calls can be measured in milliseconds and summed to give the frame time. Unfortunately, because of the way GPU's work, the more detailed your measurements become, the more difficult it becomes to get accurate measurements. Which is one of the reasons that FPS stays around regardless of it's accuracy.</p>
<p>For example, measuring how long it takes to submit a draw call is not the same as measuring how long the draw itself takes since the draw won't happen until the GPU is instructed to do the actual work. This means setting up a lot of finicky GPU timing measurements which vary wildly between API's.</p>
<p>But it is worth the effort, a well instrumented program can give very nice data about it's internal timings.</p>
<p>An alternative is to use one of the manufacturer specific GPU performance modeling tools. They will often give much of the detailed data you are looking for (plus a whole lot more).</p>

CC BY-SA 4.0
2024-05-28T04:45:25.767Z
I know that about measuring the actual time a draw call takes. You forgot to add that a driver may cache GL commands, hence the nature of any GL command is asynchronous.That said,your post should be a comment (multiple, given its length, I guess :D) since it does not really answer my question why orphaning would be faster (even visually faster) than `glBufferSubdata()`.I tried with larger datasets, where the FPS drops significantly just to check if I can visually perceive the difference between the two methodologies and indeed,it is there.Please provide more info on the performance of the two.
rbaleksandar
CC BY-SA 4.0
2024-05-28T09:56:40.347Z
So you asked two questions, one of those questions was about timing and your method was fps so I was responding to that. Also, when you say "that a driver may cache GL commands", this is what I was referring to when I said that measuring the draw submit isn't the same as measuring the actual work and is the point of the entire next paragraph talking about measuring work done on the gpu.
pmw1234
CC BY-SA 4.0
2024-05-28T14:11:17.957Z
I know what you meant. I just confirmed. :P As for the two questions: my main topic is why is the orphaning faster than updating existing sub-regions. The last part (regarding what to measure) comes due to me not being sure if my measurements are correct. If I have measured nonsense, than the results will be skewed and my main question will be completely invalidated.
rbaleksandar
CC BY-SA 4.0
2024-05-28T15:29:41.813Z
I would encourage you to dig a little deeper into the performance measuring area of GPU's. It seems like you have taken the first steps. Knowing the exact area where the performance bottleneck is would enable you to ask a more pinpoint question and really zero on why on technique is performing better then the other.
pmw1234
CC BY-SA 4.0
2024-05-27T12:31:32.357Z
2024-05-27T12:31:32.357Z
pmw1234
<p>I recently conducted an experiment, where a large scene was split into two types of mesh data - static (the terrain) and dynamic (lots of low poly trees). I evaluated two memory layouts and update mechanisms for the dynamic data, namely</p>
<ul>
<li>a single large buffer, where the first part stores the terrain and the rest - the trees - here I employed <code>glBufferSubdata()</code> to leave the terrain alone, while changing the trees</li>
<li>two buffers with the first storing the terrain, while the latter - the trees - here I employed <code>glBufferData()</code> with <code>NULL</code> to orphan the buffer responsible for the trees.</li>
</ul>
<p>I created two data sets using Blender's hair particle system to randomly generate a specific number of trees on top of my mesh. The first data set consists of 10 subsets (each containing 10 000 trees), while the second - 10 subsets with increasing number of randomly placed trees (10, 30, 70, 100, 300, 700, 1000, 3000, 7000 and 10000). In order to prevent overflow in my single buffer solution, for the randomly placed trees I took the largest subset (here 10000) in order to calculate the total size (e.g. bytes for the vertices in my terrain + vertices in the largest subset will provide the total number of bytes for my VBO).</p>
<p>I measured the FPS and CPU processing time for 10s with all the data pre-loaded in the RAM (as NumPy arrays) and changing the VBO, IBO etc. for the VAO every single iteration of my game loop (using PyGame). I got the following results using my Intel 11th Gen UHD integrated GPU:</p>
<ul>
<li><strong>Intel 11th Gen UHD</strong>
<ul>
<li>same sized sets
<ul>
<li>using <code>glBufferSubdata()</code>
<a href="https://i.sstatic.net/4aq2nOzL.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/4aq2nOzL.png" alt="CPU processing time, subdata, same size, Intel" /></a>
<a href="https://i.sstatic.net/pzNvbmVf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/pzNvbmVf.png" alt="FPS, subdata, same size, Intel" /></a></li>
<li>using <code>glBufferData()</code> with <code>NULL</code> (orphaning)
<a href="https://i.sstatic.net/pzzT8Slf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/pzzT8Slf.png" alt="CPU processing time, orphan, same size, Intel" /></a>
<a href="https://i.sstatic.net/yrSHQfB0.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/yrSHQfB0.png" alt="FPS, orphan, same size, Intel" /></a></li>
</ul>
</li>
<li>different sized sets
<ul>
<li>using <code>glBufferSubdata()</code>
<a href="https://i.sstatic.net/3UC4julD.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/3UC4julD.png" alt="CPU processing time, subdata, diff size, Intel" /></a>
<a href="https://i.sstatic.net/6Y0yHuBM.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/6Y0yHuBM.png" alt="FPS, subdata, diff size, Intel" /></a></li>
<li>using <code>glBufferData()</code> with <code>NULL</code> (orphaning)
<a href="https://i.sstatic.net/gwM27fzI.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/gwM27fzI.png" alt="CPU processing time, orphan, diff size, Intel" /></a>
<a href="https://i.sstatic.net/7o3UP5Me.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/7o3UP5Me.png" alt="FPS, subdata, diff size, Intel" /></a></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>For the single buffer solution I use <code>GL_DYNAMIC_DRAW</code>, while in the second case I use <code>GL_STATIC_DRAW</code> for the buffer that holds the terrain and <code>GL_STREAM_DRAW</code> for the one with the trees. I do know that it is highly dependent on the implementation of OpenGL in the GPU's driver whether these usage hints are even taken into consideration.</p>
<p>I am trying to figure out why orphaning is always faster. The single buffer solution using <code>glBufferSubdata()</code> does not change size throughout the experiment. The only (major) calculation I see here that can be of some consequence to the dip in performance is the offset I need to add for the indices of the tree subset that is copied to my IBO (we are talking a couple of millions of indices). I do not re-allocate the big buffer because of the way I have calculated its size (largest subset).</p>
<p>When it comes to the orphaning, regardless of whether I used differently or equally sized data sets, I have almost double the performance, which - at least to me - doesn't make sense unless the <code>GL_STREAM_DRAW</code> has such insane magic effects.</p>
<p>I also conducted the same experiment on a dedicated Nvidia RTX 3080 Mobiile and got very similar results. In terms of the main question I couldn't get more information that will help me out. In terms of the values (CPU processing time as well as FPS) being very similar I explained with the way integrated GPU works and the absence of DMA in my setup for the case with the Nvidia GPU.</p>
<p>I would also appreciate advice on what to actually measure, since - from what I have read online - measuring FPS might be nice for those flashy presentations from GPU manufacturers but it is not that accurate.</p>

<opengl><performance>
Possible reason for buffer orphaning being faster than using glBufferSubdata even when changing the size of that data?
rbaleksandar
# Possible reason for buffer orphaning being faster than using glBufferSubdata even when changing the size of that data?

(Asked by: username_0 on 2024-05-27)

I recently conducted an experiment, where a large scene was split into two types of mesh data - static (the terrain) and dynamic (lots of low poly trees). I evaluated two memory layouts and update mechanisms for the dynamic data, namely

* a single large buffer, where the first part stores the terrain and the rest - the trees - here I employed `glBufferSubdata()` to leave the terrain alone, while changing the trees
* two buffers with the first storing the terrain, while the latter - the trees - here I employed `glBufferData()` with `NULL` to orphan the buffer responsible for the trees.

I created two data sets using Blender's hair particle system to randomly generate a specific number of trees on top of my mesh. The first data set consists of 10 subsets (each containing 10 000 trees), while the second - 10 subsets with increasing number of randomly placed trees (10, 30, 70, 100, 300, 700, 1000, 3000, 7000 and 10000). In order to prevent overflow in my single buffer solution, for the randomly placed trees I took the largest subset (here 10000) in order to calculate the total size (e.g. bytes for the vertices in my terrain + vertices in the largest subset will provide the total number of bytes for my VBO).

I measured the FPS and CPU processing time for 10s with all the data pre-loaded in the RAM (as NumPy arrays) and changing the VBO, IBO etc. for the VAO every single iteration of my game loop (using PyGame). I got the following results using my Intel 11th Gen UHD integrated GPU:

* **Intel 11th Gen UHD**
  + same sized sets
    - using `glBufferSubdata()`
      [![CPU processing time, subdata, same size, Intel](https://i.sstatic.net/4aq2nOzL.png)](https://i.sstatic.net/4aq2nOzL.png)
      [![FPS, subdata, same size, Intel](https://i.sstatic.net/pzNvbmVf.png)](https://i.sstatic.net/pzNvbmVf.png)
    - using `glBufferData()` with `NULL` (orphaning)
      [![CPU processing time, orphan, same size, Intel](https://i.sstatic.net/pzzT8Slf.png)](https://i.sstatic.net/pzzT8Slf.png)
      [![FPS, orphan, same size, Intel](https://i.sstatic.net/yrSHQfB0.png)](https://i.sstatic.net/yrSHQfB0.png)
  + different sized sets
    - using `glBufferSubdata()`
      [![CPU processing time, subdata, diff size, Intel](https://i.sstatic.net/3UC4julD.png)](https://i.sstatic.net/3UC4julD.png)
      [![FPS, subdata, diff size, Intel](https://i.sstatic.net/6Y0yHuBM.png)](https://i.sstatic.net/6Y0yHuBM.png)
    - using `glBufferData()` with `NULL` (orphaning)
      [![CPU processing time, orphan, diff size, Intel](https://i.sstatic.net/gwM27fzI.png)](https://i.sstatic.net/gwM27fzI.png)
      [![FPS, subdata, diff size, Intel](https://i.sstatic.net/7o3UP5Me.png)](https://i.sstatic.net/7o3UP5Me.png)

For the single buffer solution I use `GL_DYNAMIC_DRAW`, while in the second case I use `GL_STATIC_DRAW` for the buffer that holds the terrain and `GL_STREAM_DRAW` for the one with the trees. I do know that it is highly dependent on the implementation of OpenGL in the GPU's driver whether these usage hints are even taken into consideration.

I am trying to figure out why orphaning is always faster. The single buffer solution using `glBufferSubdata()` does not change size throughout the experiment. The only (major) calculation I see here that can be of some consequence to the dip in performance is the offset I need to add for the indices of the tree subset that is copied to my IBO (we are talking a couple of millions of indices). I do not re-allocate the big buffer because of the way I have calculated its size (largest subset).

When it comes to the orphaning, regardless of whether I used differently or equally sized data sets, I have almost double the performance, which - at least to me - doesn't make sense unless the `GL_STREAM_DRAW` has such insane magic effects.

I also conducted the same experiment on a dedicated Nvidia RTX 3080 Mobiile and got very similar results. In terms of the main question I couldn't get more information that will help me out. In terms of the values (CPU processing time as well as FPS) being very similar I explained with the way integrated GPU works and the absence of DMA in my setup for the case with the Nvidia GPU.

I would also appreciate advice on what to actually measure, since - from what I have read online - measuring FPS might be nice for those flashy presentations from GPU manufacturers but it is not that accurate.

**Tags:** opengl, performance


---

## 1 answers

### Answer by username_1 on 2024-05-27. Score: 0

This started out as a comment and became to long so I am posting it as an answer.

Regarding what to measure: Usually measuring how many milliseconds a particular step takes not only gives decent performance information, it can help narrow in on the exact area that is taking up the most time. FPS can be computed from average frame time. Individual calls can be measured in milliseconds and summed to give the frame time. Unfortunately, because of the way GPU's work, the more detailed your measurements become, the more difficult it becomes to get accurate measurements. Which is one of the reasons that FPS stays around regardless of it's accuracy.

For example, measuring how long it takes to submit a draw call is not the same as measuring how long the draw itself takes since the draw won't happen until the GPU is instructed to do the actual work. This means setting up a lot of finicky GPU timing measurements which vary wildly between API's.

But it is worth the effort, a well instrumented program can give very nice data about it's internal timings.

An alternative is to use one of the manufacturer specific GPU performance modeling tools. They will often give much of the detailed data you are looking for (plus a whole lot more).

> **Comments:**
> **username_0**: I know that about measuring the actual time a draw call takes. You forgot to add that a driver may cache GL commands, hence the nature of any GL command is asynchronous.That said,your post should be a comment (multiple, given its length, I guess :D) since it does not really answer my question why orphaning would be faster (even visually faster) than `glBufferSubdata()`.I tried with larger datasets, where the FPS drops significantly just to check if I can visually perceive the difference between the two methodologies and indeed,it is there.Please provide more info on the performance of the two.  
> **username_1**: So you asked two questions, one of those questions was about timing and your method was fps so I was responding to that. Also, when you say "that a driver may cache GL commands", this is what I was referring to when I said that measuring the draw submit isn't the same as measuring the actual work and is the point of the entire next paragraph talking about measuring work done on the gpu.  
> **username_0**: I know what you meant. I just confirmed. :P As for the two questions: my main topic is why is the orphaning faster than updating existing sub-regions. The last part (regarding what to measure) comes due to me not being sure if my measurements are correct. If I have measured nonsense, than the results will be skewed and my main question will be completely invalidated.  
> **username_1**: I would encourage you to dig a little deeper into the performance measuring area of GPU's. It seems like you have taken the first steps. Knowing the exact area where the performance bottleneck is would enable you to ask a more pinpoint question and really zero on why on technique is performing better then the other.  

---

