38

I am using OpenGL ES 2.0, but I think it is also relevant to non-ES: how to know what "usage" to choose when creating a VBO?

This particular VBO will be used for 1 to 4 times before completely updated, and I am not sure if I must pick GL_STREAM_DRAW or GL_DYNAMIC_DRAW.

genpfault
  • 51,148
  • 11
  • 85
  • 139
lvella
  • 12,754
  • 11
  • 54
  • 106
  • possible duplicate of [Is using Vertex Buffer Object's for very dynamic data a good idea performance-wise?](http://stackoverflow.com/questions/4090276/is-using-vertex-buffer-objects-for-very-dynamic-data-a-good-idea-performance-wi) – bobobobo Sep 18 '12 at 19:15

5 Answers5

35

Well, according to the OpenGL API you should use DYNAMIC_DRAW.

STREAM
You should use STREAM_DRAW when the data store contents will be modified once and used at most a few times.

STATIC
Use STATIC_DRAW when the data store contents will be modified once and used many times.

DYNAMIC
Use DYNAMIC_DRAW when the data store contents will be modified repeatedly and used many times.

Make sure to update the VBO with glBufferSubData()

Veger
  • 37,240
  • 11
  • 105
  • 116
murk003
  • 375
  • 3
  • 9
  • 6
    Considering that wording, "at most a few times", I think I should use `GL_STREAM_DRAW`, because 1 to 4 times seems a few to me... – lvella Apr 15 '16 at 20:20
19

The usage flag is a hint, not a enforcement. Or in other words: Things don't break if you use a "wrong" flag. So I suggest you try all 3: STATIC_DRAW, STREAM_DRAW and DYNAMIC_DRAW and choose the one that gives you best performance – and it's very likely that they will tie.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 16
    This is an useful practical tip, but I'd still like to hear what is the difference in "intended" use for the two. Some GPUs might exploit it. – Kos Nov 27 '11 at 09:49
  • 4
    When they created the distinction, they might have had some possible optimizations in mind, otherwise there would be no point in it. What are those? – lvella Jun 20 '12 at 12:32
  • @lvella: I think the reference manual is quite clear about it: http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml under the heading "Description" – datenwolf Jun 20 '12 at 13:00
  • 4
    @datenwolf "This enables the GL implementation to make more intelligent decisions that may significantly impact buffer object performance." It seems to me very non-specific and elusive. – lvella Jun 20 '12 at 13:07
  • @lvella: Well, above that you can't really tell more, as any kind of optimization depends strongly on the OpenGL implementation (read as GPU + driver) in question. The choices varied may be the way DMA transfers are carried out, cache line utilization etc. Basically this is meant to be a black box to the user. – datenwolf Jun 20 '12 at 13:21
  • 4
    @bobobobo: This is indeed the case. In fact, after so many programs using them in wrong ways the AMD/ATI drivers do completely ignore this hint and choose the best strategy by analyzing the program's behavior. In case of doubt I'd go with DYNAMIC_DRAW as default. Also the OpenGL specification really is not very clear about this. The problem is, one has to specify one of those flags. It would really make sense to make it valid to set the GL_DONT_CARE flag of glHint there, as well. – datenwolf Sep 18 '12 at 19:56
  • @datenwolf D'you know what man, you're right. `GL_DYNAMIC_DRAW` is absolutely useless. With a [painful debugging session I recently had](http://stackoverflow.com/questions/12539864/how-do-i-properly-update-a-vertex-array-in-opengl-es-2-0/12543132) to try and get dynamic vertex buffers to work, I concluded that you _can't_ do dynamic vertex buffers on the current ios 5.1, and sticking with vertex arrays was the only way I could get things to work. – bobobobo Sep 23 '12 at 01:40
11

Besides the answers given so far, and although it has nothing directly to do with GLES, I's like to paste this bit from issue 2 of the ARB_buffer_storage extension (introduces along with desktop GL 4.4):

2) The new flags don't directly map to the parameter for glBufferData and one cannot be expressed in terms of the other. Does that matter?

Most applications get usage wrong and they're only hints anyway. The flags are hard and fast rules that must be followed. They serve a different purpose. The idea here is to allow the implementation to not have to second guess the application and to perform less tracking, and for the application to have more control. We define BufferData in terms of BufferStorage with the most liberal allowed flags (essentially, anything goes), but still pass the hint to the implementation to allow it to continue to second guess the application.

The problem with these flags has always been that every implementation might have different ideas on how to optimize the different paths suggested by the usage hint, and each application seem to have different expectations of how these optimization works.

Nvidias desktop GL driver will in a debug profile print some of the decisions it made for the buffer objects, especially if they are stored in client RAM or directly on the GPU. When playing around with this I got the following:

Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) has been mapped in HOST memory.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) stored in VIDEO memory has been updated.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) has been mapped in HOST memory.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) stored in SYSTEM HEAP memory has been updated.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations.
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).
Buffer detailed info: Buffer object 5 (bound to GL_PIXEL_UNPACK_BUFFER_ARB, usage hint is GL_STATIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).

What I did here was using a PBO to stream texture updates to the GPU, with one update per frame via mapping the buffer. The natural choice here would be using GL_STREAM_DRAW, but I specified GL_STATIC_DRAW. What the driver did was giving me some VRAM backed buffer initially, and doing I/O mapping for the first two updates I did. But then, it changed its mind and uses a client-backed buffer - giving me exactly the result I would have gotten if I had asked for GL_STREAM_DRAW in the first place. What we see here is an example for the second guessing the quoted text above was about.

All of this is highly implementation specific. And that is also part of the reason the aforementioned GL extension was created - which will give the programmer much more control over such things. However, this extension is, as far as I know, not available in the realm of OpenGL ES.

derhass
  • 43,833
  • 2
  • 57
  • 78
8

GL_STREAM_DRAW is used if you are going to call glBufferData() often - glBufferData() completely refreshes contents of buffer, allowing opengl for some optimisations, e.g. letting opengl upload new data while old is still in use: Buffer Object Streaming

GL_STATIC_DRAW is used if you are not going to change contents of buffer often

GL_DYNAMIC_DRAW is used if you are going to change buffer partially, for example with glBufferSubData().

Choosing wrong option may decrease perfomance, but nothing more, as far as i know.

Most likely those options will affect the location of the memory - RAM or VRAM, as well as some policies about working with the allocated memory (group writes first and then send data, or write immediatelly). RAM is directly writable by CPU, but is slower to read(and don't even think of modifying it) from GPU as it has to go through the PCI-e. The VRAM is the one on the GPU itself; its not directly writable by CPU (until recently, or unless you are AMD) - instead a special hardware on GPU should copy the data in batches to the VRAM from RAM.

user369070
  • 600
  • 1
  • 5
  • 9
2

For IOS, information about VBO is here in apple developer site. According to their docs GL_DYNAMIC_DRAW and GL_STREAM_DRAW are equivalent.

But I think your solution is more close to GL_DYNAMIC_DRAW since GL_DYNAMIC_DRAW is for vertex buffers that are rendered many times, and whose contents change during the rendering loop.

mert
  • 1,090
  • 13
  • 26
  • Actually if you read what you posted, it says `In iOS, GL_DYNAMIC_DRAW and GL_STREAM_DRAW are equivalent.`. – Tara Feb 10 '19 at 14:11
  • yes you're right but still it might be useful for writing platform agnostic code. – mert Feb 14 '19 at 16:28
  • For GL_STREAM_DRAW it says: `GL_STREAM_DRAW is for vertex buffers that are rendered a small number of times and then discarded.` 4 is a pretty small number I'd say. For GL_DYNAMIC_DRAW it says: `GL_DYNAMIC_DRAW is for vertex buffers that are rendered many times, and whose contents change during the rendering loop.` So I'd say the correct flag would be GL_STREAM_DRAW. However IDK what "discarded" means in this context. Btw, I can confirm that it makes no difference on Nvidia hardware either. And as some other commenter pointed out, AMD ignores the flag too. – Tara Feb 16 '19 at 07:57