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.
Related
I have this class to add Sprites to my game:
class Pickup {
public:
Pickup::Pickup()
{
Texture healthTexture;
healthTexture.loadFromFile("health.png");
m_Sprite.setTexture(healthTexture);
}
Sprite Pickup::getSprite()
{
return m_Sprite;
}
private:
Sprite m_Sprite;
};
I use Pickup nameSprite() to add another sprite to my game. But every time I do this (I tried with different images, I used if(!healthTexture.loadFromFile(..))to see if the problem is with the image) I only see a white rectangle instead of what I wanted, and nothing seems to be wrong. My question is: what is the cause for the link problem?
The SFML documentation states:
The texture argument refers to a texture that must exist as long as
the sprite uses it. Indeed, the sprite doesn't store its own copy of
the texture, but rather keeps a pointer to the one that you passed to
this function. If the source texture is destroyed and the sprite tries
to use it, the behaviour is undefined.
The Texture Object you create and load is local to your constructor and destroyed at its end, so once it is actually used later in your programs execution, the pointer/reference kept by the Sprite-Object is dangling.
To avoid the issue you could, for instance, save the Texture as an additional member in your Pickup class.
As pointed out by Lorence Hernandez in an insightful comment below, this would not, however, be an exceedingly good idea. Each instance of Pickup would hold its own texture instance, despite the textures being the same, wasting memory. Furthermore, Pickup could no longer use the default copy operations, as a copied Pickup's Sprite instance would subsequently refer to the texture instance in the original object.
A better approach would be to move the handling of this issue, i.e. management of texture instances and their lifetime, outside the Pickup class itself.
There is a multitude of possible solutions ranging from simple functions doing internal caching to more complicated resource manager classes.
The former could be as simple as the following snippet:
const Texture& load(const std::string &filename)
{
static std::map<std::string,std::unique_ptr<Texture>> textures;
auto &tex_ptr=textures[filename];
if(!tex_ptr)
tex_ptr=std::make_unique<Texture>(filename);
return *tex_ptr;
}
This simplistic version does, of course, have a minor "leak" as unused textures will never be freed during the programs execution.
Googling "texture manager sfml" will yield many examples and tutorials regarding the latter, for instance this rather old unofficial one in SFML's github. It manages sf::Image, not sf::Texture, but the same general ideas apply.
When creating multiple objects on screen (With different vertex lists, not re-using the same vertices) would you define a separate buffer description for each new set of vertices then call DrawIndexed()?
Currently, I'm trying to wrap this up in a function. I'm a bit confused as how to abstract "ownership" from a local matrix to each new instance of geometry buffer:
Additionally, is calling DrawIndexed()multiple times (for each object) in a class member acceptable methodology , or is calling DrawIndexed() and referencing the start element.
To sum up, what is the standard (or similar) for drawing multiple transformable geometry in DirectX 11?
Edit: Pseudo-code welcome if necessary; I think I've an idea, but nervous about implementation. (Whether or not it's optimized)
The purpose of this question was to find the way around a perceived limitation to the DirectX11 pipeline that only one Vertex and Index Buffer can be accepted into the pipeline. After some coding, the sandbox world of C++ and the DirectX11's sandbox mentality stands consistent, and the pipeline accepts as many buffers as necessary.
The problem was resolved, storing an object data class and a global dynamic structure logging all objects and their properties registered into the world. The object class created the "ownership" through natural data separation per class instance.
For future eyes.
I have a c++ (c++11) library I'm writing (an OpenGL graphics engine).
My question revolves around good programming techniques for registering an event listener.
I have class relationships like so:
Program --has--> SceneManager --has--> ShaderManager --has-->* Shader
The Shader class allows other objects to register themselves as a ShaderBindListener, which means that whenever the shader has it's bind() method called, it will notify any listeners.
The ShaderManager Class is the one that an outside library has access to, and from which they can create new Shader objects.
Now, I want each Shader object to have the Program object as a ShaderBindListener, so that when a Shader is bound, the Program object is notified and can pass matrix data, etc to the Shader on the GPU.
My initial solution was to have the Program object pass a pointer to itself to the SceneManager, which passes the pointer to the ShaderManager, which then stores it. Whenever a new Shader is then created, the ShaderManager adds the Program as a listener.
This works just fine - but it seems - I don't know, a bit wrong in terms of design.
Maybe I'm just being pedantic - but does this seem like good design to you guys?
There are a few options, the pros and cons for which are often debatable and depends on your style.
Singleton
If a process will only ever have one instance of Program, then you could make Program a singleton. This way, you don't need to pass the pointers around.
An intermediate object
Instead of passing the this pointer through, you could have it pass through an object which encapsulates Program and manages the event handling of it. That way, the other classes don't need to know about Program, they just need the interface for the event class.
In fact, if you aren't averse to using Boost, then they have just what you're looking for: the Signals2 library.
According to wikipedia prototype pattern is :
The prototype pattern is a creational design pattern used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to:
Avoid subclasses of an object creator in the client application, like the abstract factory pattern does.
Avoid the inherent cost of creating a new object in the standard way (e.g., using the new keyword) when it is prohibitively expensive for a given application.
I saw certain demo codes of this pattern in C++ all of them are using copy constructor.
Can anyone explain how point number two applies(in general as well as in context of C++) as we are using copy constructor anyways in clone function. If it can be done without copy constructor then an example code snippet would be great.
You can copy without dynamic allocation. For example, here's a cloning that only happens in a local scope:
Foo prototype;
void local()
{
Foo x = prototype; // first copy
x.mutate();
Foo y = x; // another copy
}
No dynamic allocation is used, ever.
It is true that return new Foo(*this); also makes a copy, but what's more important is that that object is allocated dynamically. That's the cost that your article to which is alluding.
In a game I've been making in Java, I ran into an interesting situation that fit the bill of a prototype pattern quite well. You see, I had this Animation object that stored a container of images to flip through, as well as some other data that tracked how long since the last frame was rendered, which frame it was on, if the animation was running or not, etc.
I found that for multiple characters to use the same Animation object was causing problems. If two characters shared an animation, they would turn on and turn off the animation at conflicting times for each other. I would have guys standing still with walking animations, or moving with standing animations. Creation of the animation objects were costly and time consuming what with creating the sprites, setting the ammount of time they would display for, creating an interval queue of images, etc.
Instead, I made the Animation object a prototype object. If an Animation clones itself, It shares the original collection of frames with all other animations since those are immutable, but also expensive to construct. Instead the new objects would share this immutable base, but have their own information of which frame to draw and when.
Think of it like a projector. When it get's cloned, the new projector might have it's own information on if it's running or not, which frame it's on, etc, but it may be using the same piece of film that the original projector is using. The reason why they don't trip each other up is that the film is immutable. (and expensive to create)
In all honesty, the usage of the prototype in this manner is a great way to implement a flyweight pattern. Objects that share Objects that are expensive to create. If you "clone" them, they would be instantiated with their new transient state, but still share those expensive base objects with it's creator.
Calling the copy constructor for object which isn't use dynamic memory inside itself is much more faster then perform any allocation in dynamic memory via new. Because allocation in dynamic memory is a kind of system call.
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.