PDA

View Full Version : Vertex array object



Pswin
01-19-2009, 01:41 PM
hi

how can i use ARB_vertex_array_object extension (please help with sample code)

Dark Photon
01-20-2009, 08:03 AM
how can i use ARB_vertex_array_object extension (please help with sample code)

Read this: ARB_vertex_array_object (http://www.opengl.org/registry/specs/ARB/vertex_array_object.txt)

It's just like anything else in GL. gen, bind, setup. Then when you want to re-use, just bind it.



if ( vao )
glBindVertexArray( vao );
else
{
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
<setup vertex array pointers and enables>
}

Jan
01-20-2009, 08:30 AM
Did anyone try this extension yet? Does it give noticeable speed-improvements? Does anyone know, wheter nVidia's Linux-drivers already expose it?

Dark Photon
01-20-2009, 09:33 AM
Did anyone try this extension yet? Does it give noticeable speed-improvements? Does anyone know, wheter nVidia's Linux-drivers already expose it?
Tried. No diff here. I'm using it on NVidia-Linux (so yes, it's exposed). 8800GTX + 3.73GHz hyperthread dual core.

However IIRC my test case at the time was primarily lots of client arrays with some VBOs and display lists mixed in, and this was on a fairly fast CPU. May see some benefit on other configs/loads. I'd be interested to hear more from NVidia/others about that.

Vaguely recall reading somewhere that VAOs main goal was to optimize away the expensive binding overhead of VBOs to vertex attribs. So maybe better results with 100% VBOs.

Jan
01-20-2009, 11:28 AM
This extension is so easy to use, i just implemented it myself.

Well, some stumble stones:
When you use VAOs, you STILL need to BIND the GL_ELEMENT_ARRAY_BUFFER and GL_ARRAY_BUFFER_ARB AFTER you have bound your VAO. Otherwise it crashes. Seems these states are not stored inside the VAO. However, you do not need to enable arrays and set up pointers anymore. They might want to mention this somewhere (in the spec?), took me some digging.

Another problem is, that because of the retared way vertex-attrib-arrays are bound to shaders, one needs to have a VAO for EACH combination of vertex-array and bound shader. In my case that makes about 100 VAOs. Otherwise, you guessed it, it crashes.

Now, for the performance part, i use VBOs only, no DL, no IM no client-side arrays. I took the biggest mesh, that i could find, reduced resolution to a small window and switched VAOs on and off on-the-fly to test the difference.

It is: zero

There is really NO difference whatsoever, neither good nor bad. I should mention, that this is on a Geforce 9600, Core 2 Quad 2.4 GHz, Vista 32 Bit, latest drivers (installed today).

So i guess, either this part of the pipeline is never the bottleneck for me, or the drivers are not yet optimized to take advantage of the extension. But maybe one of my cores is less under stress with VAOs, don't know.

Anyway it is very easy to add (took me 45 minutes including debugging and performance testing), so i quite like it.


Jan.

Groovounet
01-20-2009, 11:39 AM
When you use VAOs, you STILL need to BIND the GL_ELEMENT_ARRAY_BUFFER and GL_ARRAY_BUFFER_ARB AFTER you have bound your VAO. Otherwise it crashes

You just need to bound GL_ELEMENT_ARRAY_BUFFER, GL_ARRAY_BUFFER_ARB isn't a really "bounding point". Even without VAO you can just before you glDraw*** use glBindBuffer(GL_ARRAY_BUFFER, 0).

It's actually what I do to be sure that the "glVertexAttribPointer" are always set to the right buffers.

To test this feature, I think it's better to use small mesh and change the VAO as more a possible. Basically, just load 2 diferents meshes, and render them 10000 times. But each time change the VAO used. It will be something like
- Render Mesh 1
- Render Mesh 2
- Render Mesh 1
- Render Mesh 2
- Render Mesh 1
- Render Mesh 2
- etc...

I don't know about the current efficiency but on time ... it will become more efficient.

Jan
01-20-2009, 04:04 PM
Yeah, i know if one wanted to really test it properly, your idea would be better, but in my application a huge mesh means to switch the VAO more often, because each VBO contains 2^16 vertices max, so the bigger the mesh, the more VBOs i have, and thus more changes. It is always difficult to benchmark a feature with an existing engine/application, because your bottleneck is often somewhere else (in my case fillrate and pixel shader computations are definitely the limiting factors, rather than polygon throughput or CPU usage).

Anyway, from a theoretical standpoint i find this extension more than overdue (just like direct state access), so i am happy it is finally available.

Jan.

Groovounet
01-21-2009, 02:57 AM
Interesting!

Do you think that this limited size buffers are still useful considering VAO and mapped buffer range ?

Jan
01-21-2009, 04:44 PM
Well, i did a very small test. I can switch buffer-splitting on and off (at creation time of the buffer), so i switched it off and tried again comparing speed with and without VAO. In some very few cases VAO gave a speed improvement (from 46 to 49 FPS). But in general there was no difference.

Using unsigned short indices and thus only up to 2^16 vertices per buffer does give you quite a speed improvement on all hardware. Especially also on ATI, which does not benefit from glDraw_Range_Elements, at all. I tested this a while back, with big meshes and on especially with VRAM sizes smaller than your working set, this does improve performance in any case.

The thing about VAOs is, even if they would allow for the driver to optimize that you only use a subset of your data, this does not automatically imply, that such optimizations are in place. With a limited VBO size the driver can be really stupid and it still gives you better speed. Also with an offset into a buffer you only limit the lower end, not the upper. There is no way to tell the driver, that this VAO is only used to operated on n vertices from the given buffer, it must assume, that drawcalls will index all data starting behind the offset. Only with glDrawRangeElments you can make this more clear to the driver, but the next drawcall might access further data, thus it might be more efficient to simply load the whole buffer right away.

IIRC "mapped buffer range" only applies to writing to buffers, i am only talking about pure rendering. For updating buffers the mapped buffer ranges are certainly a very sensible improvement.


Well, to make this long story short, yes, it seems that smaller buffers are for now still worth the effort.

Jan.

Dark Photon
01-22-2009, 06:52 AM
When you use VAOs, you STILL need to BIND the GL_ELEMENT_ARRAY_BUFFER and GL_ARRAY_BUFFER_ARB AFTER you have bound your VAO. Otherwise it crashes.
In my case, I was not rebinding ARRAY_BUFFER for VBO cases. That was apparently stored in the VAO, which makes sense. You could have 1 VBO for each vertex attrib. In that case, VAOs would make no sense unless the VBO bindings were cached with the offsets.

But like you I was of course binding ELEMENT_ARRAY_BUFFER as usual, as that's part of the draw call and not the vertex array bindings.

Jan
01-22-2009, 10:40 AM
You are absolutely right, just tested it myself. Thanks for the info.

Jan.

alder
01-25-2009, 10:16 AM
ELEMENT_ARRAY_BUFFER_BINDING should also be stored in the VAO as it is part of table 6.8, so after initial set up you just need to bind the VAO and draw.

jeffb
01-25-2009, 11:06 PM
To be clear, the ELEMENT_ARRAY_BUFFER binding *is* part of the VAO and the ARRAY_BUFFER binding *is not* part of the VAO.

Jan
01-26-2009, 02:36 AM
Strange, because it works with the one but not the other. Maybe a a bug in nVidia's implementation? I will need to check that again...

Jan.

Groovounet
01-26-2009, 04:00 AM
From my tests I would say that are ELEMENT_ARRAY_BUFFER not part of VAO because I need to bind them separately. One other weird behaviours is that the binding order matter.

This works:


glBindVertexArray(vertexArrayName);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);

glDrawElements(
GL_TRIANGLES,
mesh.elementCount(),
GL_UNSIGNED_SHORT,
0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);


This doesn't work, it crashs:


glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);
glBindVertexArray(vertexArrayName);

glDrawElements(
GL_TRIANGLES,
mesh.elementCount(),
GL_UNSIGNED_SHORT,
0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);


And including glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName) during the VAO creation doesn't work either.

Groovounet
01-26-2009, 04:07 AM
And "ARRAY_BUFFER binding" are definitely part of the VAO ... even I would expect it isn't just to be able to change array buffers after VAO creation but we can't. "Highest number of a kind of object" title is going to win by VAOs.

alder
01-26-2009, 11:21 AM
Looks like the VAO extension and core 3.0 are not aligned or there's a mistake in either one. The extension excludes CLIENT_ACTIVE_TEXTURE from the stored states, but 3.0 leaves out table 6.10 meaning CLIENT_ACTIVE_TEXTURE and ARRAY_BUFFER_BINDING.
In the 181.22 driver Nvidia seems to have implemented the extension following 3.0 spec.

jeffb
01-29-2009, 08:11 PM
From my tests I would say that are ELEMENT_ARRAY_BUFFER not part of VAO because I need to bind them separately.

<snip>

This doesn't work, it crashs:


glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);
glBindVertexArray(vertexArrayName);

glDrawElements(
GL_TRIANGLES,
mesh.elementCount(),
GL_UNSIGNED_SHORT,
0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);




When you do glBindVertexArray(vertexArrayName), that swaps out the whole VAO so rather than using elementBufferName you'll use whatever element_array_buffer was last bound to vertexArrayName (assuming you haven't since then implicitly detached it by deleting it or something like that).

jeffb
01-29-2009, 08:12 PM
ARRAY_BUFFER is a selector just like CLIENT_ACTIVE_TEXTURE. You should go with what the 3.0 spec says in this case.

Groovounet
01-30-2009, 08:25 AM
Unfortunalety as Jan and I said earlier, it doesn't seams that GL_ELEMENT_ARRAY_BUFFER is attached to the VAO at least on nVidia implementation. If we don't bind it at draw call, it crashes.

Mars_999
01-30-2009, 11:32 PM
SO what is the consensus so far? Worth the time or waste of time? This is for GL2.1 RC not GL3.0 RC...

Jan
01-31-2009, 02:43 AM
Waste of time, if you ain't got it ;-) You do not gain any speed up so far.

Depending on your architecture it is however extremely easy to plug in, i only had to modify 10 lines of code. So, if you are bored, you could implement it in the hope, that it will give you a speed up in the future.

Jan.

Groovounet
01-31-2009, 06:40 AM
I'm not a fan either. For the speed improvement side we might haven't used a good testing method. What I'am more concerned is more the feature side. I doesn't provide anything more than my "display list state object" so what's the point of it? If display lists are really been removed so we need other macro immutable state objects for blending (or a shader :D), depth and stencil test and the rasterizer.

Well I keep the code ... because ... well I keep it.

Mars_999
01-31-2009, 11:45 AM
I wonder would this make a bigger difference in situations where you were calling 1000's of different glVertex* and glBindBuffer calls each frame?

jeffb
02-09-2009, 05:52 PM
Unfortunalety as Jan and I said earlier, it doesn't seams that GL_ELEMENT_ARRAY_BUFFER is attached to the VAO at least on nVidia implementation. If we don't bind it at draw call, it crashes.

Can you post more complete source, or a repro app?

Groovounet
02-10-2009, 06:17 AM
@jeffb: Did you manage to attach element buffer in VAO on your side?

I can certainly reproduce it in a sample.

jeffb
02-10-2009, 07:02 PM
yes, it works for me.

Groovounet
02-11-2009, 10:29 AM
On which graphics card ? nVidia ?

Groovounet
02-11-2009, 06:31 PM
I have just updated my drivers to 182.05 one and it seams to work now. I was using 180.xx drivers ...

Just a bug I guest!

aqnuep
08-17-2009, 08:21 AM
Just to clarify a few things about what you were talking here:

Both the OpenGL 3.0 specification and the ARB_vertex_array_object extension says that both ELEMENT_ARRAY_BUFFER and ARRAY_BUFFER bindings are part of the VAO as well as the VertexAttribPointer specifications. This makes sense. Anything else is just a driver bug. In my case on ATI, Catalyst 9.7 drivers don't even generate a VAO for me when I use GenVertexArrays. Maybe there are also some problems with the NVIDIA drivers as well.

The main purpose of this feature is to reduce CPU and driver time by not having to issue several GL commands. Any rooms for optimization based on this feature for a particular vendor is beyond the scope of this extension. It is meant to reduce required GL calls and simplify the framework and I think that's achieved. And of course, it's very easy to adopt it :)

Correction: VAO DOES work with Catalyst 9.7 but GLee was screwed up. I hate these libraries. I searched a lot to find windowing and extension libraries that supports OpenGL 3.0+ contexts. I heard that GLFW and SDL both support 3.0 context creation but only using the latest SVN code. First I've tried SDL but didn't manage to compile it under Windows. Next tried GLFW which has support for 3.0 context creation but it was not working. So I've corrected GLFW and now it works. For extension library I used GLee first but as I said it sucks, because for some reason VAO was not working on it (yes, and of course I also had to modify it a bit to work with 3.0+ contexts). Finally now I'm using the corrected version of GLFW and GLEW as extension library and till now everything looks fine. Sorry if I'm off-topic but maybe you can also take advantage of this information :)

Heiko
08-17-2009, 09:49 AM
I'm using GenVertexArrays on my Ati card:



GLuint vao;
glGenVertexArrays(1, &amp;vao);
glBindVertexArray(vao);

GLuint buffer;
glGenBuffers(1, &amp;buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// adding data to the array buffer with glBufferSubData

glVertexAttribPointer(
0,
sizeOfAttrib(0),
GL_FLOAT,
GL_FALSE,
strideOfAttrib(0),
offsetOfAttrib(0)
);

glVertexAttribPointer(
1,
sizeOfAttrib(1),
GL_FLOAT,
GL_FALSE,
strideOfAttrib(1),
offsetOfAttrib(1)
);

// drawing

glBindVertexArray(d_vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

Works like a charm at least with Linux Ati Catalyst 9.6 and 9.7, perhaps I already used it on 9.5 (Radeon HD4870).

Yes, I used the same code on 9.5 as well, I remembered that I mailed AMD about it back than, because on 9.5 it didn't work if I selected a forward compatible context (only with non-forward compatible context). Problems were solved in 9.6.

alder
08-20-2009, 12:50 PM
Remember to move the glEnableVertexAttribArray calls to you VAO initialization unless you're planning to enable different attrib arrays for different draw calls.

Pswin
08-23-2009, 12:04 AM
thnks to all for helping

Heiko
08-24-2009, 11:41 PM
Remember to move the glEnableVertexAttribArray calls to you VAO initialization unless you're planning to enable different attrib arrays for different draw calls.

Will do that, I think I've tried it in one of the first Ati OpenGL 3.0 drivers, but it didn't work back than (or I missed something). Haven't looked back on it since.

Pswin
08-26-2009, 03:50 AM
glBindVertexArryay take runtime error:



Unhandled exception at 0x00000000 in DEngine_Test2.exe:
0xC0000005: Access violation.


my code for working with it is:


GLuint temp;
glGenVertexArrays(1,&amp;temp);

if ( temp == 0 )
{
DLogger.Log("can not create VAO");
return;
}

glBindVertexArray(temp);
glBufferData(GL_VERTEX_ARRAY,m_uStride,vertics,GL_ STATIC_DRAW);

felpy
08-26-2009, 08:08 AM
I'm using VBOs in a -more or less- modern ACER notebook (5612) and I noticed no improvement at all. Then I came to realize that graphic cards in notebooks usually work with shared system memory. żDoes that mean VBOs won't give any improvement at all on any notebook?

Pswin
08-26-2009, 09:02 AM
no, problem is not in the, data saved in VRAM or RAM

vbo's are fast because they dont use system bus for sending data, this is true for shared ram's and vram