OpenGL has a number of functions that directly take pointers. Some of them read data from those pointers, others write data to those pointers.
However, OpenGL functions often don't execute immediately. Usually, when you draw something, it takes a while for the drawing to finish.
So how do I know when OpenGL is finished with a pointer I give it?
All OpenGL functions, with the exception noted below, will be finished with any pointer you give it upon that function's return. So glReadPixels will have finished all pixel reading and format conversion upon its return. This is why asynchronous pixel transfer is so important for reading operations. It allows OpenGL to not do that, to not synchronize with the GPU.
The only exception to this rule is every function that ends in the word "Pointer". Things like glVertexAttribPointer, glTexCoordPointer, and the like. When you use client-side memory with these functions (no longer legal in core profile OpenGL 3.2+), these functions store a pointer to that memory. Therefore, you must ensure that this pointer is valid for as long as you intend to render with those vertex attributes.
After each rendering call using client-memory, OpenGL requires that the implementation have finished reading from client memory by the time the rendering function returns. So you can call glDrawArrays, then delete the pointers in question. And as long as you don't make another draw call until you've changed those pointers, you're fine. This means OpenGL has to have copied out all relevant vertex data by the time the rendering call returns (one of the reasons why using buffer objects is faster).
Related
I don't understand what the purpose is of binding points (such as GL_ARRAY_BUFFER) in OpenGL. To my understanding glGenBuffers() creates a sort of pointer to a vertex buffer object located somewhere within GPU memory.
So:
glGenBuffers(1, &bufferID)
means I now have a handle, bufferID, to 1 vertex object on the graphics card. Now I know the next step would be to bind bufferID to a binding point
glBindBuffer(GL_ARRAY_BUFFER, bufferID)
so that I can use that binding point to send data down using the glBufferData() function like so:
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW)
But why couldn't I just use the bufferID to specifiy where I want to send the data instead? Something like:
glBufferData(bufferID, sizeof(data), data, GL_STATIC_DRAW)
Then when calling a draw function I would also just put in which ever ID to whichever VBO I want the draw function to draw. Something like:
glDrawArrays(bufferID, GL_TRIANGLES, 0, 3)
Why do we need the extra step of indirection with glBindBuffers?
OpenGL uses object binding points for two things: to designate an object to be used as part of a rendering process, and to be able to modify the object.
Why it uses them for the former is simple: OpenGL requires a lot of objects to be able to render.
Consider your overly simplistic example:
glDrawArrays(bufferID, GL_TRIANGLES, 0, 3)
That API doesn't let me have separate vertex attributes come from separate buffers. Sure, you might then propose glDrawArrays(GLint count, GLuint *object_array, ...). But how do you connect a particular buffer object to a particular vertex attribute? Or how do you have 2 attributes come from buffer 0 and a third attribute from buffer 1? Those are things I can do right now with the current API. But your proposed one can't handle it.
And even that is putting aside the many other objects you need to render: program/pipeline objects, texture objects, UBOs, SSBOs, transform feedback objects, query objects, etc. Having all of the needed objects specified in a single command would be fundamentally unworkable (and that leaves aside the performance costs).
And every time the API would need to add a new kind of object, you would have to add new variations of the glDraw* functions. And right now, there are over a dozen such functions. Your way would have given us hundreds.
So instead, OpenGL defines ways for you to say "the next time I render, use this object in this way for that process." That's what binding an object for use means.
But why couldn't I just use the bufferID to specifiy where I want to send the data instead?
This is about binding an object for the purpose of modifying the object, not saying that it will be used. That is... a different matter.
The obvious answer is, "You can't do it because the OpenGL API (until 4.5) doesn't have a function to let you do it." But I rather suspect the question is really why OpenGL doesn't have such APIs (until 4.5, where glNamedBufferStorage and such exist).
Indeed, the fact that 4.5 does have such functions proves that there is no technical reason for pre-4.5 OpenGL's bind-object-to-modify API. It really was a "decision" that came about by the evolution of the OpenGL API from 1.0, thanks to following the path of least resistance. Repeatedly.
Indeed, just about every bad decision that OpenGL has made can be traced back to taking the path of least resistance in the API. But I digress.
In OpenGL 1.0, there was only one kind of object: display list objects. That means that even textures were not stored in objects. So every time you switched textures, you had to re-specify the entire texture with glTexImage*D. That means re-uploading it. Now, you could (and people did) wrap each texture's creation in a display list, which allowed you to switch textures by executing that display list. And hopefully the driver would realize you were doing that and instead allocate video memory and so forth appropriately.
So when 1.1 came around, the OpenGL ARB realized how mind-bendingly silly that was. So they created texture objects, which encapsulate both the memory storage of a texture and the various state within. When you wanted to use the texture, you bound it. But there was a snag. Namely, how to change it.
See, 1.0 had a bunch of already existing functions like glTexImage*D, glTexParamter and the like. These modify the state of the texture. Now, the ARB could have added new functions that do the same thing but take texture objects as parameters.
But that would mean dividing all OpenGL users into 2 camps: those who used texture objects and those who did not. It meant that, if you wanted to use texture objects, you had to rewrite all of your existing code that modified textures. If you had some function that made a bunch of glTexParameter calls on the current texture, you would have to change that function to call the new texture object function. But you would also have to change the function of yours that calls it so that it would take, as a parameter, the texture object that it operates on.
And if that function didn't belong to you (because it was part of a library you were using), then you couldn't even do that.
So the ARB decided to keep those old functions around and simply have them behave differently based on whether a texture was bound to the context or not. If one was bound, then glTexParameter/etc would modify the bound texture, rather than the context's normal texture.
This one decision established the general paradigm shared by almost all OpenGL objects.
ARB_vertex_buffer_object used this paradigm for the same reason. Notice how the various gl*Pointer functions (glVertexAttribPointer and the like) work in relation to buffers. You have to bind a buffer to GL_ARRAY_BUFFER, then call one of those functions to set up an attribute array. When a buffer is bound to that slot, the function will pick that up and treat the pointer as an offset into the buffer that was bound at the time the *Pointer function was called.
Why? For the same reason: ease of compatibility (or to promote laziness, depending on how you want to see it). ATI_vertex_array_object had to create new analogs to the gl*Pointer functions. Whereas ARB_vertex_buffer_object just piggybacked off of the existing entrypoints.
Users didn't have to change from using glVertexPointer to glVertexBufferOffset or some other function. All they had to do was bind a buffer before calling a function that set up vertex information (and of course change the pointers to byte offsets).
It also mean that they didn't have to add a bunch of glDrawElementsWithBuffer-type functions for rendering with indices that come from buffer objects.
So this wasn't a bad idea in the short term. But as with most short-term decision making, it starts being less reasonable with time.
Of course, if you have access to GL 4.5/ARB_direct_state_access, you can do things the way they ought to have been done originally.
Now that we have direct state access I wonder why there are no updated glDraw* DSA functions.
For example glDrawArrays is dependent to the current VAO, so why is there no glNamedDrawArrays?
Do I still have call
glBindVertexArray(vao);
glDrawArrays(..);
or is there another way?
glDraw* is just tell OGL to draw something under current context and that maybe related many states like Shader, Blender, VBO/VAO, Z/Stencil, Texture, etc.. Even a tiny change may bring different render result, so you can image DSA glDraw* will be a long function parameter list, that's not good. For example, you want to change cull face from CW to CCW, maybe you need to find the corresponding parameter in a long function call, and change it. Be note, OGL is most C-like, and default parameter feature of function is limited, each time you call DSA glDraw*, you need to have a long function call with most same values, that will make you crazy.
As #Andon M. Coleman mentioned, DSA aimed for reduce the call sequence of general OGL function call type: bind->modify->unbind, and DSA only need 1 API call. That will reduce the CPU time, especial you have a very large OGL API calls.
Thanks
An
When should i call glDeleteBuffersARB ? Should I do it when application ends? Can I somehow automatize the process of deletion vertex buffer object? For instance something like smart_ptr does.
Never. You should never call glDeleteBuffersARB. Buffer objects have been core GL functionality for upwards of a decade now; if you're still using the ARB-suffixed extensions functions, STOP. If you're follow a tutorial that uses them, again STOP; it's clearly too old to be useful.
Now, when should you use glDeleteBuffers? You should use it at the same time you would delete for a regular C++ object. That is, use it when you are finished with the object. When you have no more use for it and want to get rid of it.
so can I create class for vbo with destructor which will delete vbo object? And then create objects as smart_ptr to automatize everything?
You could, but it's not going to buy you all that much. Also, you run the very real risk of waiting to delete the object until it's too late.
It is illegal to call any OpenGL function before the OpenGL context is created (and made current) or whenever a GL context is not current (for example, after you've destroyed the GL context). Attempts to do so are not good.
If you use shared_ptr to manage these resources, it becomes theoretically possible for them to outlive the actual OpenGL context. That's bad. Personally, I would prefer a more rigid management scheme, one that firmly ties the lifetime of the GL objects to that of the context.
I'm reading along in this tutorial and i get down towards the end in how to use Vertex Buffers and i see that the vertex buffer which I generated and called glBindBuffer on once already i have to bind a second time:
glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle);
I'm still very new to openGL (like 3 days) so I'm trying to wrap my mind around how a lot of these things work. I spend most of my time on khronos or opengl.org reading about the commands, but I couldn't figure out why this one gets called twice. any hints? Thanks.
Does that particular example strictly need the second bind? No. OpenGL retains state, so if a buffer object is bound to a target, then it will remain bound until you bind something else to that target.
However, what happens if you insert code after the creation of the buffer that creates a second buffer? After all, you might want to have two objects. Or 10. Or however many you want; they don't have to share buffer objects.
Once you do that, your code breaks because the buffer that your code expects to be bound isn't actually bound. Therefore, unless you're good at managing state and really know what you're doing (and if you're still following tutorials, the answer is "no"), you should set whatever state you need to do what you intend.
Therefore, if you intend to draw from a particular buffer, you should bind it and set the appropriate state (the gl*Pointer calls).
You have to bind and unbind the buffer to copy to it from 'C' and draw with it from openGL.
Think of it as locking/unlocking between the program and the graphics.
So the sequence is
create
bind
stuff data
unbind
bind
display
unbind
Brief : The second one usualy unbinds the first one.
If no buffer object with name buffer exists, one is created with that name. When a buffer object is bound to a target, the previous binding for that target is automatically broken.
Buffer object names are unsigned integers. The value zero is reserved, but there is no default buffer object for each buffer object target. Instead, buffer set to zero effectively unbinds any buffer object previously bound, and restores client memory usage for that buffer object target (if supported for that target). Buffer object names and the corresponding buffer object contents are local to the shared object space of the current GL rendering context; two rendering contexts share buffer object names only if they explicitly enable sharing between contexts through the appropriate GL windows interfaces functions.
Reference : https://www.opengl.org/sdk/docs/man/html/glBindBuffer.xhtml
Right now, I'm modelling some sort of little OpenGL library to fool around with graphic programming etc. Therefore, I'm using classes to wrap around specific OpenGL function calls like texture creation, shader creation and so on, so far, so good.
My Problem:
All OpenGL calls must be done by the thread which owns the created OpenGL Context (at least under Windows, every other thread will do nothing and create an OpenGL error). So, in order to get an OpenGL context, I firstly create an instance of a window class (just another wrapper around the Win API calls) and finally create an OpenGL context for that window. That sounded quiet logical to me. (If there's already a flaw in my design that makes you scream, let me know...)
If I want to create a texture, or any other object that needs OpenGL calls for creation, I basically do this (the called constructor of an OpenGL object, example):
opengl_object()
{
//do necessary stuff for object initialisation
//pass object to the OpenGL thread for final contruction
//wait until object is constructed by the OpenGL thread
}
So, in words, I create an object like any other object using
opengl_object obj;
Which then, in its contructor, puts itself into a queue of OpenGL objects to be created by the OpenGL context thread. The OpenGL context thread then calls a virtual function which is implemented in all OpenGL objects and contains the necessary OpenGL calls to finally create the object.
I really thought, this way of handling that problem, would be nice. However, right now, I think I'm awfully wrong.
The case is, even though the above way works perfectly fine so far, I'm having troubles as soon as the class hierarchy goes deeper. For example (which is not perfectly, but it shows my problem):
Let's say, I have a class called sprite, representing a Sprite, obviously. It has its own create function for the OpenGL thread in which the vertices and texture coordinates are loaded into the graphic cards memory and so on. That's no problem so far.
Let's further say, I want to have 2 ways of rendering sprites. One Instanced and one through another way. So, I would end up with 2 classes, sprite_instanced and sprite_not_instanced. Both are derived from the sprite class, as they both are sprite which are only rendered differently. However, sprite_instanced and sprite_not_instanced need further OpenGL calls in their create function.
My Solution so far (and I feel really awful about it!)
I have some kind of understanding how object generation in c++ works and how it affects virtual functions. So I decided to use the virtual create function of the class sprite only to load the vertex data and so on into the the graphics memory. The virtual create method of sprite_instanced will then do the preparation to render that sprite instanced.
So, if I want write
sprite_instanced s;
Firstly, the sprite constructor is called and after some initialisation, the constructing thread passes the object to the OpenGL thread. At this point, the passed object is merely a normal sprite, so sprite::create will be called and the OpenGL thread will create a normal sprite. After that, the constructing thread will call the constructor of sprite_instanced, again do some initialisation and pass the object to the OpenGL thread. This time however, it's a sprite_instanced and therefore sprite_instanced::create will be called.
So, if I'm right with the above assumption, everything happens exactly as it should, in my case at least. I spend the last hour reading about calling virtual functions from constructors and how the v-table is build etc. I've ran some test to check my assumption, but that might be compiler-specific so I don't rely on them 100%. In addition, it just feels awful and like a terrible hack.
Another Solution
Another possibility would be implementing factory method in the OpenGL thread class to take care of that. So I can do all the OpenGL calls inside the constructor of those objects. However, in that case, I would need a lot of functions (or one template-based approach) and it feels like a possible loss of potential rendering time when the OpenGL thread has more to do than it needs to...
My Question
Is it ok to handle it the way I described it above? Or should I rather throw that stuff away and do something else?
You were already given some good advice. So I'll just spice it up a bit:
One important thing to understand about OpenGL is, that it is a state machine, which doesn't need some elaborate "initialization". You just use it, and that's about it. Buffer Objects (Textures, Vertex Buffer Objects, Pixel Buffer Objects) may make it look different, and most tutorials and real world applications indeed fill Buffer Objects at application start.
However it is perfectly fine to create them during regular program execution. In my 3D engine I use the free CPU time during the double buffer swap for asynchronous uploads into Buffer Objects (for(b in buffers){glMapBuffer(b.target, GL_WRITE_ONLY);} start_buffer_filling_thread(); SwapBuffers(); wait_for_buffer_filling_thread(); for(b in buffers){glUnmapBuffer(b.target);}).
It's also important to understand that for simple things like sprites should not given its own VBO for each sprite. One normally groups large groups of sprites in a single VBO. You don't have to draw them all together, since you can offset into the VBO and make partial drawing calls. But this common pattern of OpenGL (geometrical objects sharing a buffer object) completely goes against that principle of your classes. So you's need some buffer object manager, that hands out slices of address space to consumers.
Using a class hierachy with OpenGL in itself is not a bad idea, but then it should be some levels higher than OpenGL. If you just map OpenGL 1:1 to classes you gain nothing but complexity and bloat. If I call OpenGL functions directly or by class, I'll still have to do all the grunt work. So a texture class should not just map the concept of a texture object, but it should also take care of interacting with Pixel Buffer Objects (if used).
If you actually want to wrap OpenGL in classes I strongly recommend not using virtual functions but static (means on the compilation unit level) inline classes, so that they become syntactic sugar the compiler will not bloat up too much.
The question is simplified by the fact a single context is assumed to be current on a single thread; actually there can be multiple OpenGL contexts, also on different threads (and while we're at, we consider context name spaces sharing).
First all, I think you should separate the OpenGL calls from the object constructor. Doing this allow you to setup an object without carrying about OpenGL context currency; successively the object could be enqueued for creation in the main rendering thread.
An example. Suppose we have 2 queues: one which holds Texture objects for loading texture data from filesystem, one which hold Texture objects for uploading texture data on GPU memory (after having loaded data, of course).
Thread 1: The texture loader
{
for (;;) {
while (textureLoadQueue.Size() > 0) {
Texture obj = textureLoadQueue.Dequeue();
obj.Load();
textureUploadQueue.Enqueue(obj);
}
}
}
Thread 2: The texture uploader code section, essentially the main rendering thread
{
while (textureUploadQueue.Size() > 0) {
Texture obj = textureUploadQueue.Dequeue();
obj.Upload(ctx);
}
}
The Texture object constructor should looks like:
Texture::Texture(const char *path)
{
mImagePath = path;
textureLoadQueue.Enqueue(this);
}
This is only an example. Of course each object has different requirements, but this solution is the most scalable.
My solution is essentially described by the interface IRenderObject (the documentation is far different from the current implementation, since I'm refactoring alot at this moment and the development is at a very alpha level). This solution is applied to C# languages, which introduce additional complexity due the garbage collection management, but the concept are perfectly adaptable to C++ language.
Essentially, the interface IRenderObject define a base OpenGL object:
It has a name (those returned by Gen routines)
It can be created using a current OpenGL context
It can be deleted using a current OpenGL context
It can be released asynchronously using an "OpenGL garbage collector"
The creation/deletion operations are very intuitive. The take a RenderContext abstracting the current context; using this object, it is possible to execute checks that can be useful to find bug in object creation/deletion:
The Create method check whether the context is current, if the context can create an object of that type, and so on...
The Delete method check whether the context is current, and more important, check whether the context passed as parameter is sharing the same object name space of the context that has created the underlying IRenderObject
Here is an example on the Delete method. Here the code works, but it doesn't work as expected:
RenderContext ctx1 = new RenderContext(), ctx2 = new RenderContext();
Texture tex1, tex2;
ctx1.MakeCurrent(true);
tex1 = new Texture2D();
tex1.Load("example.bmp");
tex1.Create(ctx1); // In this case, we have texture object name = 1
ctx2.MakeCurrent(true);
tex2 = new Texture2D();
tex2.Load("example.bmp");
tex2.Create(ctx2); // In this case, we have texture object name = 1, the same has before since the two contexts are not sharing the object name space
// Somewhere in the code
ctx1.MakeCurrent(true);
tex2.Delete(ctx1); // Works, but it actually delete the texture represented by tex1!!!
The asynchronous release operation aim to delete the object, but not having a current context ( infact the method doesn't take any RenderContext parameter). It could happen that the object is disposed in a separate thread, which doesn't have a current context; but also, I cannot rely on the gargage colllector (C++ doesn't have one), since it is executed in a thread with I have no control. Furthermore, it is desiderable to implement the IDisposable interface, so application code can control the OpenGL object lifetime.
The OpenGL GarbageCollector, is executed on the thread having the right context current.
It is always bad form to call any virtual function in a constructor. The virtual call will not be completed as normal.
Your data structures are very confused. You should investigate the concept of Factory objects. These are objects that you use to construct other objects. You should have a SpriteFactory, which gets pushed into some kind of queue or whatever. That SpriteFactory should be what creates the Sprite object itself. That way, you don't have this notion of a partially constructed object, where creating it pushes itself into a queue and so forth.
Indeed, anytime you start to write, "Objectname::Create", stop and think, "I really should be using a Factory object."
OpenGL was designed for C, not C++. What I've learned works best is to write functions rather than classes to wrap around OpenGL functions, as OpenGL manages its own objects internally. Use classes for loading your data, then pass it to C-style functions which deal with OpenGL. You should be very careful generating/freeing OpenGL buffers in constructors/destructors!
I would avoid having your objects insert themselves into the GL thread's queue on construction. That should be an explicit step, e.g.
gfxObj_t thing(arg) // read a file or something in constructor
mWindow.addGfxObj(thing) // put the thing in mWindow's queue
This lets you do things like constructing a set of objects and then putting them all in the queue at once, and guarantees that the constructor ends before any virtual functions are called. Note that putting the enqueue at the end of the constructor does not guarantee this, because constructors are always called from top-most class down. This means that if you queue an object to have a virtual function called on it, derived classes will be enqueued before their own constructors begin acting. This means you have a race condition which can cause action on an uninitialized object! A nightmare to debug if you don't realize what you've done.
I think the problem here isn't RAII, or the fact that OpenGL is a c-style interface. It's that you're assuming sprite and sprite_instanced should both derive from a common base. These problems occur all the time with class hierarchies and one of the first lessons I learned about object orientation, mostly through many errors, is that it's almost always better to encapsulate than to derive. EXCEPT that if you're going to derive, do it through an abstract interface.
In other words, don't be fooled by the fact that both of these classes have the name "sprite" in them. They are otherwise totally different in behaviour. For any common functionality they share, implement an abstract base that encapsulates that functionality.