如何解决这个设计缺陷?

时间:2017-05-29 14:56:44

标签: c++ glew

开发一个teris游戏我得出的结论是,使用通常的MVC模式可能会使我的代码混乱,以及由于OpenGL在GLEW下工作的方式,使其更难以构建。相反,我提出了这个整洁的修改,也依赖于观察者模式,这会更有意义,至少在短期内(图像不反映完整的类树):
makeshift architecture

解释:
- 每个框都是一个类,Engine包含Entities的实例,Game包含Figure的实例。
- Figure继承Entity
- Engine观察GameGame由观察员与Figures耦合。

它应该如何工作:
理想情况下,我应该实例化Engine,它将设置GLEW和GLFW以及构成窗口的所有其他内容,然后创建一个Game对象,在新线程中,它将创建一个数字,并通知启动绘图循环的引擎,当设置该数字时,通过Observer将对象指针传递给Engine
这样可以很好地工作,我可以通过继承Entity来添加各种数字,数字不会从屏幕上掉落,因为每个坐标更新都会通过Game,我可以,如果有必要的话,可能会给每个人物一个独特的着色器。

它是如何工作的:
初始化引擎,初始化游戏,在另一个线程中调用图,然后抛出

atioglxx.dll: 0xC0000005: Access violation reading location 0x00000728.

当被要求访问任何OpenGL功能时。
我怀疑这是因为Figure并不知道所有支持功能都是在Engine中启动的。我无法在Figure再次这样做。我可以将与View有关的所有内容移动到Engine,但之后我将无法设置单独的着色器,并且我必须为{{1}内的每个数字构建VAO(顶点数组对象) }。
那么如何尽可能少地引入错误呢?

1 个答案:

答案 0 :(得分:0)

简短的回答是,给定上下文的所有OpenGL调用都需要在同一个线程上。更长的答案就在路上......

首先,Entities需要能够使用GL调用绘制自己。您不能将一个线程中的绘图代码与另一个线程混合,OpenGL客户端状态将不正确。 (将OpenGL视为'C'状态机)。

其次,您需要按帧缓冲实体状态。当您在Engine主题中开始下一帧时,Game可能会或可能不会完成提交绘制调用。因此,您需要一些同步方式来提交帧的所有Entity个状态。这有点棘手,因为您希望避免可能会使管道停滞或导致阻塞的同步原语(例如互斥)。

您可以阅读使用双缓冲管道的Doom III source code,以便向Engine后端提交绘图调用。诀窍是Doom在主线程上执行大部分操作,然后在后端(Engine)线程上执行Draw Calls并在{{{Entities上提交绘制状态(Game)。 1}}主线程。然后它等待Engine线程完成并交换缓冲区。

阅读Metal和Vulkan多线程。这些非常相似。

需要在Engine上加载资源并返回要引用的实体的句柄(着色器,纹理,静态几何等)。