我最近决定在OpenGL对象中添加一些RAII,直到我意识到OpenGL被设置为状态系统是徒劳的和矛盾的。现在,我实际上想要为涉及OpenGL对象的游戏实现一个类,如下所示:
class RenderTarget: public boost::noncopyable{
public:
virtual ~RenderTarget();
protected:
clear(const ColorSet& color);
copy_to(const RenderTarget& target) = 0;
copy_from(const RenderTarget& target) = 0;
attach(const RenderTarget& target);
detach(const RenderTarget& target);
private:
//set of opengl framebuffers/renderbuffers/etc. ?
};
正如你所看到的,我希望这个抽象包含一组opengl帧缓冲区,但问题是因为opengl是一个状态机,每当我想调用任何成员函数时,我要么: 假设成员帧缓冲区被绑定(坏),每次调用函数时调用bind / unbind(昂贵),或者暴露bind()/ unbind()接口(丑陋,暴露OpenGL语义)。我有点被困在这里。我是否以错误的方式思考这个问题?
答案 0 :(得分:1)
我实际上有一个类似于你为我的项目讨论的设计,而不是使用全局数组我有一个类作为状态机的接口,并提供一些类似于不推荐的状态堆栈的功能
class FrameBufferBindState {
friend class eTB_RenderContext;
protected:
FrameBufferBindState (void) {
reset ();
}
void reset (void) {
bound = NULL;
swap_count = 0;
req_count = 0;
}
void bind (eTB_FrameBuffer* fbo);
void push (void);
void pop (void);
eTB_FrameBuffer* bound;
int swap_count;
int req_count;
std::stack <eTB_FrameBuffer *> stack;
};
我有一个名为eTB_RenderContext
的类,它包含引擎可以绑定的每个基本对象类的类实例(请注意,其中一些类本身也包含绑定,例如程序对象绑定了着色器对象他们)。
我会跟踪bind (...)
被调用的次数(req_count
)与实际必须更改绑定的次数(swap_count
)以衡量批次效率。我还有一个用于绑定和状态的堆栈机制,以使一些算法更容易。
VertexArrayBindState vertex_array_;
ProgramBindState program_;
FrameBufferBindState framebuffer_;
SamplerBindState* samplers_; // Minimum: 80 in GL4
TextureBindState* texture_images_; // Minimum: 80 in GL4
答案 1 :(得分:1)
RAII仍然有利于OpenGL中的资源管理(纹理需要ID等,如果您在游戏中达到下一级并加载新资产,则应该释放它们)。这些任务很少进行,面向对象的开销对响应性的影响很小。
但是对于单独渲染和中帧状态管理,封装会产生很多低效率(例如,为每个对象上传颜色和纹理绑定),而良好的OpenGL性能需要最小化状态更改。即使检测和省略冗余状态更改也无济于事,您需要按排序顺序提交几何图形,而不是根据某些抽象对象模型进行分组。