我最近决定向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 FrameBuffers,但是问题是,由于OpenGL是状态机,只要我想调用任何成员函数,我都必须:假设成员FrameBuffer是绑定的(不良),每次调用函数时调用绑定/打开绑定(昂贵),或揭示bind()/unbind()接口(丑陋,露出OpenGL语义)。我有点被困在这里。我是错误的方式吗?
我实际上的设计与您正在为我的项目讨论的设计类似,只是而不是使用全局数组,我有一个作为状态机的接口并提供的类某些功能类似于弃用状态堆栈。
示例绑定状态:
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;
};
i有一个名为eTB_RenderContext
的类,其中包含每个基本对象类似类的类实例(请注意,请注意,其中一些类也包含绑定本身,例如程序对象具有绑定到其上的阴影对象)。
i跟踪调用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
raii仍然适合OpenGL中的资源管理(例如,纹理需要ID等,例如,如果您达到游戏中的下一个级别并加载新资产)。这些任务很少完成,并以对象为导向的开销对响应能力的影响很小。
但是,对于单个渲染和中框状态管理,封装会产生许多效率低下(例如,为每个对象上传颜色和纹理绑定),而良好的OpenGL性能则需要最大程度地减少状态变化。即使是冗余状态更改的检测和省略也无济于事,您需要按顺序提交几何形状,而不是根据某些抽象对象模型进行分组。