View Single Post
Old 08-06-15, 19:17   #1504
Cochrane's Avatar
Join Date: Apr 2006
Location: Germany
Posts: 16,669

Hm, weird. I'll look into it.


I promised to explain what VAOs are all about, so here it is:

Background which you probably already know: To draw something, you need textures, shaders and vertex data. Vertex array objects are about the last part. The vertex data consists of information for each vertex, such as position, color and so on (collectively known as attributes), and of the indices that tell you in which order the vertices are drawn. Both parts are stored buffer objects, also known as vertex buffer objects in this role. Generally there's two, one for the indices and one for the attributes, but you can have more, for example putting one attribute into its own buffer (OpenTomb does that for texture coordinates for animated textures. The animated attribute is one buffer, the part that stays static is another).

(Note: You always draw from a buffer object. If you think you don't, that just means the driver is creating one for you while you're not looking, which is probably slower than using your own where you know how and when it will be used.)

All very simple, but it requires an awful lot of setup for every draw call. Before any draw call, you have to say what attributes you want and for each what format it has and where to get it from. This is annoying, and it takes time.

Vertex array objects are special objects to solve this problem. A VAO simply encapsulates all that state. Conceptually, it is simply a list, telling you what attributes are enabled, their format, the buffer they're from and so on, and also what buffer to get the indices from (some people will tell you that VAOs don't contain the indices. That's just plain wrong). Binding a VAO means the driver will do all that setup for you, and generally faster and more optimized than you can (though don't expect any huge speedups here).

That's really all there is to it. It's a way of changing this code:

glBindBuffer(GL_ARRAY_BUFFER, 10);
glVertexPointer(3, GL_FLOAT, 42, 0);
glNormalPointer(GL_FLOAT, 42, 5);

glBindBuffer(GL_ARRAY_BUFFER, 9);
glTexCoordPointer(2, GL_FLOAT, 8, 0);


(example code, do not use) to this:

Tricky parts

- Some hardware doesn't support VAOs. On them, a different implementation is used that does all the manual annoying binding. Look at vertex_array.cpp for the details. manual_vertex_array in particular is a fully functional implementation of vertex array objects done on the client side. We still need the other version because OpenGL 3.2 Core Profile allows only that one.
- I'm no longer using glVertexPointer and friends. VAOs do support them, but Core Profile doesn't. Instead I use generic numbered attributes. The numbers (specified in enums) match to names of variables declared as attribute in the shader. That matching happens in shader_description.cpp (look for glBindAttribLocationARB).
- The extension has a weird history: It was created by Apple, so the functions had names like glBindVertexArrayAPPLE. Then it became part of OpenGL 3.0 and lost the APPLE suffix, so it was just glBindVertexArray. Then that was turned into an extension so older cards could support it. For that, they didn't add a suffix, so it stays glBindVertexArray there, too. Which is a long way of saying: There is no glBindVertexArrayARB. Never has been, never will be. Don't worry about it.
- The selected code will work both with the APPLE version of the extension and the official suffix-less one. This is probably irrelevant for non-Mac users, but doesn't hurt either.
- VAOs absolutely require that everything is in a vertex buffer, otherwise it doesn't work. Getting that done was the main task, and is the reason why VAOs are not yet used for the GUI (that's next).
- Since not everything is VAO yet, VAOs have to be unbound before drawing something that is not VAO yet. If you don't do that, the effect may be nothing at all (the VAO simply ignored), or a complete crash. Which one you get depends on your driver. Ah, trying to fix random crashes that only happen on some strangers computer a thousand miles away. Isn't graphics programming awesome?


In other news: I have no plans to port the Mac version OpenTomb to Apple's new graphics API Metal. That would serve no purpose whatsoever, because Metal is built to solve problems that OpenTomb doesn't have. In particular, OpenTomb doesn't spend a lot of time calling OpenGL functions (which is what Metal can reduce); it spends about 30% of its time in Character_GetHeightInfo. If you ever think performance is a problem, try optimizing that function first, either how it works or by making sure it gets called less often.


Edit to add: Fixed that bug with the frustums. I think a better fix might be possible, but I don't understand the frustum code well enough (for one thing, it seems that frustums should really be named portals unless I'm getting something very wrong), so this will have to do for now.
GŁter auf die Bahn!

Last edited by Cochrane; 08-06-15 at 20:33.
Cochrane is offline   Reply With Quote