我正在开发一款简单的安卓游戏。我想说我想用多线程来优化我的引擎。我在OpenGL ES,Android 2.2
工作现在UpdateGame()和RenderScene()在单线程中运行并在onDrawFrame(GL10 gl)中执行
我有一个RenderObject类,它有Position,Rotation,Scale和Color成员。所有RenderObject都是在我开始游戏时创建的,并存储在RenderObject数组中。
在UpdateGame()函数中,我在RenderObject数组中浏览RenderObjects并更新新的Position,Rotation,Scale和Color。
在RenderScene()函数中,我在RenderObject数组中浏览RenderObjects并使用新的Position,Rotation,Scale和Color渲染它们。
这在单线程中可以正常工作。
然后我尝试为UpdateGame()创建一个线程。
所以我的想法是:
更新线程:................渲染线程:
更新第0帧
更新第1帧................渲染帧0 ....更新并渲染并行工作
更新第2帧................渲染第1帧
更新第3帧................渲染第2帧
但首先我修改了RenderObject类,使其具有RenderPosition,RenderRotation,RenderScale和RenderColor成员。
在渲染前一帧之前复制这些成员。因此并行更新线程可以修改新的位置,旋转,缩放,颜色。
Runnable pRunnable;
Thread pThread;
public int renderframe = 0;
piblic int updateframe = 0;
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// I create a new thread in this function
pRunnable = new Runnable(){
public void run(){
while(true)
{
while( renderframe < updateframe )
{
// WAITING for render to finish so that data does not get corrupterd
}
//
// I update RenderObject Position, Rotation, Scale, Color members here
UpdateGame();
updateframe++;
}
}
};
pThread = new Thread(pRunnable);
pThread.start();
}
public void onDrawFrame(GL10 gl)
{
while( renderframe == updateframe )
{
// Wait for update to finish
}
for(int a=0;a<MAX_RENDER_OBJECTS;a++)
{
RenderObject ro = aRenderObjects[a];
// I do this in a function
ro.RenderPosition[0] = ro.Position[0];
ro.RenderPosition[1] = ro.Position[1];
ro.RenderPosition[2] = ro.Position[2];
ro.RenderPosition[3] = ro.Position[3];
// I do the same for Rotation, Scale, Color
}
renderframe++;
// When rendering scene I use RenderPosition, RenderRotation members when calling OpenGL API
RenderScene();
}
但是当我运行我的游戏时。图形不正确。看起来好像数据不同步。
有关如何在Update和Render线程之间正确同步RenderObject数据的任何建议。
谢谢。
答案 0 :(得分:0)
这种风格似乎效率低下(旋转等待循环会阻止两个线程同时工作)而且很危险(我不知道Android是如何实现这一点的,但是Java内存模型并不能保证来自一个线程的数据是可见的到另一个线程而不经过同步块。)
我的建议是:主线程是渲染线程(GL上下文是线程本地的,所以你不能从另一个线程使用它(虽然你可以在另一个线程上创建另一个上下文来执行一些数据共享)) ,并生成更新线程。然后主线程继续循环,在每次迭代时等待互斥锁。更新线程更新游戏逻辑,并创建表示必须绘制的所有内容的新对象(例如,绘图命令列表)。然后将此对象放在队列中并唤醒主线程(使用notify())。然后主线程获取绘图数据并绘制它。
如果更新循环比渲染循环快得多,你可能想要解除较旧的数据集,但是这个一般的想法应该让你开始。