Say we bind vertex attribute locations to the same values on two programs. Is it correct to use the same vertex array object to draw with these two programs?
Define "correct."
If two program objects use compatible attribute locations, then they use the same attribute locations. VAOs work off of attribute locations, so a VAO that works with one will work with another. So this will work.
In general, it is a matter of performance whether you actually take advantage of this. It's generally a good idea to avoid changing vertex array state, but it's not clear how important this is relative to other state changes. You're changing programs anyway, so not changing VAOs when you change programs will at worst be no slower and can lead to significant performance increases.
However, it is not clear how much work you should do to minimize vertex array state changes. If you can pack models into the same buffer objects with the same format, you can render all of them without VAO changing using functions like glDrawArrays or glDrawElementsBaseVertex.
I've tried using the same VAO with different shaders and I could see visual artifacts.
(The IDs of the attributes did match)
The solution was to use a new VAO for every single program.
Related
I'm facing a problem where the use of an occlusion query in combination with instanced rendering would be desirable.
As far as I understood, something like
glBeginQuery(GL_ANY_SAMPLES_PASSED, occlusionQuery);
glDrawArraysInstanced(mode, i, j, countInstances);
glEndQuery(GL_ANY_SAMPLES_PASSED);
will only tell me, if any of the instances were drawn.
What I would need to know is, what set of instances has been drawn (giving me the IDs of all visible instances). Drawing each instance in an own call is no option for me.
An alternative would be to color-code the instances and detect the visible instances manually.
But is there really no way to solve this problem with a query command and why would it not be possible?
It's not possible for several reasons.
Query objects only contain a single counter value. What you want would require a separate sample passed count for each instance.
Even if query objects stored arrays of sample counts, you can issue more than one draw call in the begin/end scope of a query. So how would OpenGL know which part of which draw call belonged to which query value in the array? You can even change other state within the query scope; uniform bindings, programs, pretty much anything.
The samples-passed count is determined entirely by the rasterizer hardware on the GPU. And the rasterizer neither knows nor cares which instance generated a triangle.
Instancing is a function of the vertex processing and/or vertex specification stages; by the time the rasterizer sees it, that information is gone. Notice that fragment shaders don't even get an instance ID as input, unless you explicitly create one by passing it from your vertex processing stage(s).
However, if you truly want to do this you could use image load/store and its atomic operations. That is, pass the fragment shader the instance in question (as an int data type, with flat interpolation). This FS also uses a uimageBuffer buffer texture, which uses the GL_R32UI format (or you can use an SSBO unbounded array). It then performs an imageAtomicAdd, using the instance value passed in as the index to the buffer. Oh, and you'll need to have the FS explicitly require early tests, so that samples which fail the fragment tests will not execute.
Then use a compute shader to build up a list of rendering commands for the instances which have non-zero values in the array. Then use an indirect rendering call to draw the results of this computation. Now obviously, you will need to properly synchronize access between these various operations. So you'll need to use appropriate glMemoryBarrier calls between each one.
Even if queries worked the way you want them to, this would be overall far more preferable than using a query object. Unless you're reading a query into a buffer object, reading a query object requires a GPU/CPU synchronization of some form. Whereas the above requires some synchronization and barrier operations, but they're all on-GPU operations, rather than synchronizing with the CPU.
Should I disable shaders attributes when switching to a program shader which uses less (or different locations of) attributes?
I enable and disable these attributes with glEnableVertexAttribArray()/glDisableVertexAttribArray().
Is there any performance impact, or could it bring some bugs, or doing enable/disable will be slower than activate all attributes and let them activated ?
The OP most likely understands the first part already, but let me just reiterate some points on vertex attributes to set the basis for the more interesting part. I'll assume that all vertex data comes from buffers, and not talk about the case where calls like glVertexAttrib3f() are used to set "constant" values for attributes.
The glEnableVertexAttribArray() and glVertexAttribPointer() calls specify which vertex attributes are enabled, and describe how the GPU should retrieve their values. This includes their location in memory, how many components they have, their type, stride, etc. I'll call the collected state specified by these calls "vertex attribute state" in the rest of this answer.
The vertex attribute state is not part of the shader program state. It lives in Vertex Attribute Objects (VAOs), together with some other related state. Therefore, binding a different program changes nothing about the vertex attribute state. Only binding a different VAO does, or of course making one of the calls above.
Vertex attributes are tied to attribute/in variables in the vertex shader by setting the location of the in variables. This specifies which vertex attribute the value of each in variable should come from. The location value is part of the program state.
Based on this, when binding a different program, it is necessary that the locations of the in variables are properly set to refer to the desired attribute. As long as the same attribute is always used for the shader, this has to be done only once while building the shader. Beyond that, all the attributes used by the shader have to be enabled with glEnableVertexAttribArray(), or by binding a VAO that contains the state.
Now, finally coming to the core of the question: What happens if attributes that are not used by the program are enabled?
I believe that having unused attributes enabled is completely legal. At least I've never seen anything in the spec that says otherwise. I just checked again, and still found nothing. Therefore, there will be no bugs resulting from having unused attributes enabled.
Does it hurt performance? The short answer is that it possibly could. Let's look at two hypothetical hardware architectures:
Architecture A has reading of vertex attribute values baked into the vertex shader code.
Architecture B has a fixed function unit that reads vertex attribute values. This fixed function unit is controlled by the vertex attribute state, and writes the values into on-chip memory, where vertex shader instances pick them up.
With architecture A, having unused attributes enabled would have no effect at all. They would simply never be read.
With architecture B, the fixed function unit might read the unused attributes. The vertex shader would end up not using them, but they could still be read from main/video memory into on-chip memory. The driver could avoid that by checking which attributes are used by the current shader, and set up the fixed function unit with only those attributes. The downside is that the state setup for the fixed function unit has to be checked/updated every time a new shader is bound, which is otherwise unnecessary. But it prevents reading unused attributes from memory.
Going one step farther, let's say we do end up reading unused attributes from memory. If and how much this hurts is impossible to answer in general. Intuitively, I would expect it to matter very little if the attributes are interleaved, and the unused attributes are in the same cache lines as used attributes. On the other hand, if reading unused attributes causes extra cache misses, it would at least use memory bandwidth, and consume power.
In summary, I don't believe there's a clear and simple answer. Chances are that having unused attributes enabled will not hurt at all, or very little. But I would personally disable them anyway. There is a potential that it might make a difference, and it's very easy to do. Particularly if you use VAOs, you can generally set up the whole vertex attribute state with a single glBindVertexArray() call, so enabling/disabling exactly the needed attributes does not require additional API calls.
I am trying to understand the meaning of a "performance tip" given in the GCW Zero OpenGL instructions:
always use vertex buffer objects (VBOs)
put vertices into one interleaved VBO, not multiple VBOs
Does this mean that I should put ALL MY OBJECTS into a single vertex buffer (and remember the start / finish index pertaining to each object). Or does it simply mean that each object should be in one vertex buffer (rather than a buffer for each attribute).
Is it normal to have multiple objects in the same vertex buffer?
Does this mean that I should put ALL MY OBJECTS into a single vertex
buffer (and remember the start / finish index pertaining to each
object)
Or does it simply mean that each object should be in one
vertex buffer (rather than a buffer for each attribute).
This "performance tip" says nothing about multiple objects. What it says is that you should put all the attributes into the same VBO, using interleaved attribute arrays. Which is likely to be the most cache efficient strategy, and a reasonable advice in the general case.
Putting multiple objects is also quite common, especially if they have only relatively few vertices. You can save a lot of state switches and ideally even draw calls that way. But it depends on the scene, of course. Combining things into the same VBO is most useful for static objects which are often drawn together.
I have a couple questions about how OpenGL handles these drawing operations.
So lets say I pass OpenGL the pointer to my vertex array. Then I can call glDrawElements with an array of indexes. It will draw the requested shapes using those indexes in the vertex array correct?
After that glDrawElements call could I then do another glDawElements call with another set of indexes? Would it then draw the new index array using the original vertex array?
Does OpenGL keep my vertex data around for the next frame when I redo all of these calls? So the the next vertex pointer call would be a lot quicker?
Assuming the answer to the last three questions is yes, What if I want to do this on multiple vertex arrays every frame? I'm assuming doing this on any more than 1 vertex array would cause OpenGL to drop the last used array from graphics memory and start using the new one. But in my case the vertex arrays are never going to change. So what I want to know is does opengl keep my vertex arrays around in-case next time I send it vertex data it will be the same data? If not is there a way I can optimize this to allow something like this? Basically I want to draw procedurally between the vertexes using indicies without updating the vertex data, in order to reduce overhead and speed up complicated rendering that requires constant procedurally changing shapes that will always use the vertexes from the original vertex array. Is this possible or am I just fantasizing?
If I'm just fantasizing about my fourth question what are some good fast ways of drawing a whole lot of polygons each frame where only a few will change? Do I always have to pass in a totally new set of vertex data for even small changes? Does it already do this anyways when the vertex data doesn't change because I notice I cant really get around the vertex pointer call each frame.
Feel free to totally slam any logic errors I've made in my assertions. I'm trying to learn everything I can about how opengl works and it's entirely possible my current assumptions on how it works are all wrong.
1.So lets say I pass OpenGL the pointer to my vertex array. Then I can call glDrawElements with an array of indexes. It will draw the
requested shapes using those indexes in the vertex array correct?
Yes.
2.After that glDrawElements call could I then do another glDawElements
call with another set of indexes? Would it then draw the new index
array using the original vertex array?
Yes.
3.Does OpenGL keep my vertex data around for the next frame when I redo
all of these calls? So the the next vertex pointer call would be a lot
quicker?
Answering that is a bit more tricky than you might. The way you ask these questions makes me to assume that uou use client-side vertex arrays, that is, you have some arrays in your system memory and let your vertes pointers point directly to those. In that case, the answer is no. The GL cannot "cache" that data in any useful way. After the draw call is finished, it must assume that you might change the data, and it would have to compare every single bit to make sure you have not changed anything.
However, client side VAs are not the only way to have VAs in the GL - actually, they are completely outdated, deprecated since GL3.0 and been removed from modern versions of OpenGL. The modern way of doing thins is using Vertex Buffer Objects, which basically are buffers which are managed by the GL, but manipulated by the user. Buffer objects are just a chunk of memory, but you will need special GL calls to create them, read or write or change data and so on. And the buffer object might very well not be stored in system memory, but directly in VRAM, which is very useful for static data which is used over and over again. Have a look at the GL_ARB_vertex_buffer_object extension spec, which orignially introduced that feature in 2003 and became core in GL 1.5.
4.Assuming the answer to the last three questions is yes, What if I want
to do this on multiple vertex arrays every frame? I'm assuming doing
this on any more than 1 vertex array would cause OpenGL to drop the
last used array from graphics memory and start using the new one. But
in my case the vertex arrays are never going to change. So what I want
to know is does opengl keep my vertex arrays around in-case next time
I send it vertex data it will be the same data? If not is there a way
I can optimize this to allow something like this? Basically I want to
draw procedurally between the vertexes using indicies without updating
the vertex data, in order to reduce overhead and speed up complicated
rendering that requires constant procedurally changing shapes that
will always use the vertexes from the original vertex array. Is this
possible or am I just fantasizing?
VBOs are exactly what you are looking for, here.
5.If I'm just fantasizing about my fourth question what are some good
fast ways of drawing a whole lot of polygons each frame where only a
few will change? Do I always have to pass in a totally new set of
vertex data for even small changes? Does it already do this anyways
when the vertex data doesn't change because I notice I cant really get
around the vertex pointer call each frame.
You can also update just parts of a VBO. However, it might become inefficient if you have many small parts which are randomliy distributed in your buffer, it will be more efficient to update continous (sub-)regions. But that is a topic on it's own.
Yes
Yes
No. As soon as you create a Vertex Buffer Object (VBO) it will stay in the GPU memory. Otherwise vector data needs to be re-transferred (an old method of avoiding this was Display Lists). In both cases the performance of subsequent frames should stay similar (but much better with the VBO method): you can do the VBO creation and download before rendering the first frame.
The VBO was introduced to provide you exactly with this functionality. Just create several VBOs. Things get messy when you need more GPU memory than available though.
VBO is still the answer, and see Modifying only a specific element type of VBO buffer data?
It sounds like you should try something called Vertex Buffer Objects. It offers the same benefits as Vertex Arrays, but you can create multiple vertex buffers and store them in "named slots". This method has much better performance as data is stored directly in Graphic Card memory.
Here is a good tutorial in C++ to start with.
I'm trying to load multiple objects into a vbo in opengl. If I want to be able to move these objects independently should I use a mesh for each object or should I load all the objects to a single mesh?
Also in my code I have...
loc1 = glGetAttribLocation(shaderP, "vertex_position");
Now I understand that this gets the vertex positions in my current program but if I want to load another object I load the mesh and then how can I get the vertex positions again but for only that mesh?
The answer is, as often, "it depends". Having one "mesh" (i.e. one buffer) per object is arguably "cleaner" but it is also likely slower. One buffer per object will make you bind a different buffer much more often. Tiny vertex buffer objects (a few dozen vertices) are as bad as huge ones (gigabytes of data). You should try to find a "reasonable" thing in between
The as of version 3.2 readily available glDrawElementsBaseVertex (also exists as instanced version) will allow you to seamlessly draw several objects or pieces from one buffer without having to fiddle with renumbering indices, and without having to switch buffers.
You should preferrably (presuming OpenGL 3.3 availability) not use glGetAttribLocation at all, but assign the attribute to a location using the layout specifier. That way you know the location, you don't need to ask every time, and you don't have to worry that "weird, unexpected stuff" might happen.
If you can't do it in the shader, use glBindAttribLocation (available since version 2.0) instead. It is somewhat less comfortable, but does the same thing. You get to decide the location instead of asking for it and worrying that the compiler hopefully didn't change the order for two different shaders.
It's generally cleaner if you use different buffers for different objects.
According to:
http://www.opengl.org/sdk/docs/man/xhtml/glGetAttribLocation.xml
This will only returned the pointer to the location of the data. You use this to bind you vertex info to the program. When you render your other object you will bind to the vbo that stores the other vertices.