Morgan Bengtsson
Morgan Bengtsson

Reputation: 1341

Automatic bind in OpenGL object wrapper

I tend to wrap OpenGL objects in their own classes. In OpenGL there is the concept of binding, where you bind your object, do something with it and then unbind it. For example, a texture:

 glBindTexture(GL_TEXTURE_2D, TextureColorbufferName);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000);
 glBindTexture(GL_TEXTURE_2D, 0);

Wrapping this would be something like:

texture->bind();
    texture->setParameter(...);
    texture->setParameter(...);
texture->unBind();

The problem here, is that I want to avoid the bind() and unBind() functions, and instead just be able to call the set methods and the GLObject will be bound automaticly.

I could just do it in every method implementation:

public void Texture::setParameter(...)
{
    this.bind();
    // do something
    this.unBind();
}

Though then I have to do that for every added method! Is there a better way, so it is automatically done before and after every method added?

Upvotes: 4

Views: 732

Answers (3)

Nicol Bolas
Nicol Bolas

Reputation: 474376

I tend to wrap OpenGL objects in their own classes.

A guy goes to the doctor and say, "It hurts whenever I raise my arm like this." So the doctor says, "Then stop raising your arm like that."

Your problem is that you're trying to provide an object-based interface to a system that is not object based. That will only end in tears and/or pain.

A far better solution would be to raise the level of your abstraction. Instead of wrapping OpenGL objects directly, wrap your graphics API. You might have some external concept of "texture" which would store an OpenGL texture object, but you wouldn't expose functions that change parameters on that texture directly. Or even indirectly.

Don't make promises with your API that you can't keep. Raise the abstraction to the point where the external code simply doesn't care what the texture's filtering mode and other parameters are.

Alternatively, have the filtering (and wrapping) be part of the object's constructor, a fixed value set at creation time.

Upvotes: 1

SigTerm
SigTerm

Reputation: 26439

The problem here, is that I want to avoid the bind() and unBind() functions

Most likely, you won't be able to get rid of them completely. glTexImage2D will require bind/unBind (or lock/unlock if you wnat DirectX-style names)

I could just do it in every method implementation:

You shouldn't do that, because you'll get massive performance drop. It is called "state trashing", if I remember correctly. If you need to modify multiple parameters, you should modify them all in one go. Calling "bind"/"unbind" frequently will be extremely inefficient and isn't recommended in performance guidelines I saw (i.e. DirectX SDK, nvidia documentation, random GDC papaers, etc).

Is there a better way, so it is automatically done before and after every method added?

Yes, there is. Cache multiple state changes and delay actual OpenGL calls till they're absolutely necessary.

I.e. if your program requests to set Min filter, Mag filter, wrap_s, wrap_t and other parameters for glTexParameter, and your texture isn't currently bound to any texutre stage, don't set parameters now. Store them in internal list (within this specific texture), and set them all at once next time texture is bound. Or when list reaches certain size, or when user calls glGetTexParameter. Once it is time to set parameters, bind texture, set parameters, and unbind it, if necessary.

There are two potential problems with this approach, though:

  1. Time spent on changing texture states might become a bit unpredictable. (because you won't be sure when exactly actual OpenGL cal will be performed).
  2. It might be harder to detect OpenGL errors using this method.
  3. If internal list uses dynamically allocated memory and frequently calls new/delete, this might result in bottleneck, because calls to new/delete can be slow. This can be solved by using fixed-size circular buffer for that internal list.

Upvotes: 2

Constantinius
Constantinius

Reputation: 35089

Maybe a context object may help here. Consider this small object:

class TextureContext {
public:
    TextureContext(char* texname) {
        glBindTexture(GL_TEXTURE_2D, texname);
    }
    ~TextureContext() {
        glBindTexture(GL_TEXTURE_2D, 0);
    }
};

This object is now used within a scope:

{
    TextureContext mycont(textname);
    mytexture->setParameter(...);
    mytexture->setParameter(...);
    mytexture->setParameter(...);
}

the object mycont only lives in the scope and calls its destructor (ant the unbind method respectively) automatically once the scope is left.

EDIT:

Maybe you can adjust the TextureContext class to take your Texture instance instead in the constructor and retrieves the texture name itself before binding the texture.

Upvotes: 5

Related Questions