如何让C ++编译器知道函数是`Idempotent`

时间:2016-12-22 16:00:12

标签: c++ opengl

我正在编写一个OpenGL C ++包装器。这个包装器旨在减少复杂和易错的使用。

例如,我目前希望用户只需关注OpenGL Context。为此,我写了一个课程gl_texture_2d。众所周知,OpenGL texture基本上有以下操作:

  1. 将其u / v参数设置为repeat / mirror,依此类推
  2. min / mag filter设为linear
  3. ...
  4. 基于此,我们有:

    class gl_texture_2d 
    {
    public:
      void mirror_u(); // set u parameter as mirror model
      void mirror_v(); // set v parameter as mirror model
      void linear_min_filter(); // ...
      void linear_mag_filter(); // ...
    };
    

    嗯,我们知道,只有当the handle of OpenGL texture object当前绑定到OpenGL context时,我们才能执行这些操作。 假设我们有一个函数执行此操作: void bind(GLuint htex); //实际上是相关GL函数的别名

    好的,我们现在可以将gl_texture_2d用法设计为:

    gl_texture_2d tex;
    bind(tex.handle());
    tex.mirror_u();
    tex.linear_min_filter();
    unbind(tex.handle());
    

    它确认了GL的逻辑,但它失去了包装的重要性,对吗?作为用户,我希望像以下一样操作:

    gl_texture_2d tex;
    tex.mirror_u();
    tex.linear_min_filter();
    

    为实现这一目标,我们必须实现以下功能:

    void gl_texture_2d::mirror_u()
    {
      glBindTexture(GL_TEXTURE_2D, handle());
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
      glBindTexture(GL_TEXTURE_2D, 0);
    }
    

    始终在内部执行绑定操作,确保操作有效。但是成本很高!

    代码:

    tex.mirror_u();
    tex.mirror_v();
    

    将扩展为一对无意义的绑定/解除绑定操作。

    有没有任何机制可以让编译器知道:

    1. 如果bind(b)紧跟bind(a)后,bind(a)可以删除;
    2. 如果bind(a)在一个区块中出现两次,则最后一个没有效果。

2 个答案:

答案 0 :(得分:1)

如果您正在使用pre-DSA OpenGL,并且您绝对必须使用自己的API直接将OpenGL调用,那么用户可能必须知道整个绑定到编辑的事情。毕竟,如果他们为了渲染目的绑定了一个纹理,那么他们会尝试修改一个,它可能会损坏当前的绑定。

因此,您应该将绑定到编辑的概念直接构建到API中。

也就是说,纹理对象(BTW, 仅限于2D纹理)实际上不应该具有修改它的功能,因为你不能修改OpenGL纹理而不绑定它(或者没有DSA,你真的应该学习)。它不应该有mirror_u等等;这些函数应该是binder对象的一部分:

bound_texture bind(some_texture, tex_unit);
bind.mirror_u();
...

bound_texture的构造函数将some_texture绑定到tex_unit。它的成员函数将修改该纹理(注意:他们需要调用glActiveTexture以确保没有人更改活动纹理单元。)

bound_texture的析构函数应该自动解除绑定纹理。但是你应该有一个release成员函数来手动取消绑定它。

答案 1 :(得分:0)

您无法在编译级别执行此操作。相反,如果你真的担心这些错误的时间成本,那么管理者对象可能就是这样:

class state_manager {
    GLuint current_texture;
    /*Maybe other stuff?*/
public:
    void bind_texture(gl_texture_2d const& tex) {
        if(tex.handle() != current_texture) {
            current_texture = tex.handle();
            glBindTexture(/*...*/, current_texture);
        }
    }
};

int main() {
    state_manager manager;
    /*...*/
    gl_texture_2d tex;
    manager.bind(tex);
    manager.bind(tex); //Won't execute the bind twice in a row!
    /*Do Stuff with tex bound*/

}