【发布时间】:2019-11-14 09:33:40
【问题描述】:
我从事在 GLSurfaceView 的视频线程中运行的 c++ 游戏(游戏的循环是 GLSurfaceView 的循环,因为它以连续模式运行)。我在如何正确处理 Activity.onPause/onResume 以及我的游戏的 nativePause 时遇到问题。在 nativePause 中,我发布了 opengl 资源和各种大数据。我没有 nativeResume,因为这是由 Android 在我调用 GLSurfaceView.onResume() 时处理的,它再次调用方法 onSurfaceCreated/onSurfaceChanged ,我在其中再次分配我的资源。
这是我现在的做法:
暂停
java中的Activity处理onPause并运行glSurfaceView的自定义nativePause方法:
@Override
protected void onPause() {
super.onPause();
glSurfaceView.nativePause();
}
nativePause 向游戏的视频循环发送异步请求。处理视频循环并释放各种资源。接下来,向主线程发送另一条消息,其中包含 nativePause 已完成的信息,我执行 GLSurfaceView.onPause(),这将停止视频线程。
onResume
这个方法实现简单,只用onResume()启动surfaceview的视频线程
@Override
protected void onResume() {
super.onResume();
glSurfaceView.onResume();
}
但问题是,onPause 对视频线程进行异步调用并返回到主线程。 Activity.onResume 通常在整个暂停机制完成之前被调用,然后它崩溃或挂起。如果游戏在视频线程中运行,我应该如何正确处理 onPause/onResume?
编辑:
Java 方面:
public class RendererWrapper implements Renderer {
public native void onSurfaceCreated();
public native void onSurfaceChanged(int width, int height);
public native void onDrawFrame();
....
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
onSurfaceCreated();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
onSurfaceChanged(width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
onDrawFrame();
}
....
}
public class VideoSurface extends GLSurfaceView {
public VideoSurface(Context context) {
super(context);
this.setEGLContextClientVersion(2);
this.renderer = new RendererWrapper();
this.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
this.setRenderer(renderer);
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
public native void nativePause();
}
RendererWrapper 中的原生 onDrawFrame() 是主游戏循环。
C++端
void nativePause() {
InputEvent *event = inputQueue.getWriteEvent();
event->type = InputEvent::PAUSE;
inputQueue.incWriteIndex();
}
void onDrawFrame() {
if (isPaused) {
return;
}
InputEvent *event = inputQueue.getReadEvent();
if (event) {
inputQueue.incReadIndex();
....
if (event->type == InputEvent::PAUSE) {
release();
return;
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
game->draw();
}
EDIT2:
class EventQueue {
public:
static const int size = 256;
volatile int readIndex;
volatile int writeIndex;
InputEvent *events;
EventQueue() {
readIndex = 0;
writeIndex = 0;
events = new InputEvent[size];
}
InputEvent* getReadEvent() {
if (writeIndex == readIndex) {
return 0; // queue empty
}
return events + readIndex;
}
InputEvent* getWriteEvent() {
if (((writeIndex + 2) & (size - 1)) == readIndex) {
return 0; // queue full
}
return events + writeIndex;
}
void incReadIndex() {
readIndex = (readIndex + 1) & (size - 1);
}
void incWriteIndex() {
writeIndex = (writeIndex + 1) & (size - 1);
}
};
【问题讨论】:
-
如果是我,我会阻止
nativePause()直到它完成。我相信在Activity.onPause()已经返回之后调用GLSurfaceView.onPause()是非法的,您可能正在找出原因。使nativePause()同步应该相当容易;您仍然可以指望您的 OpenGL 线程存在;我假设您不依赖对onDrawFrame()的任何干预调用来进行清理;您应该能够阻塞直到您的 OpenGL 线程通知条件变量或其他东西,nativePause()操作已完成。 -
谢谢,你的意思是简单的Thread.sleep()?
-
不,我的意思是使用已建立的线程通信技术。要么 1.) 将消息从线程 A 传递给线程 B,让线程 B 进行清理,然后将消息传递给线程 A(然后解除阻塞并从
nativePause()返回),或者 2.) 让线程 A 获取锁,进行清理,释放锁,然后从nativePause()返回。pthread_mutex_lock或pthread_cond_wait/pthread_cond_signal可能是您想要使用的,在这里。如果您需要帮助,最好将nativePause()的所有相关代码添加到您的问题中。 -
谢谢,我添加了nativePause现在如何工作的代码。它创建输入事件并将其放入输入队列。这个队列是在绘制线程的循环中读取的
-
看起来你已经在使用线程间通信了,所以我们为什么不坚持你已经习惯的东西。我不能确切地知道
inputQueue是什么类型的对象。你有一些文件吗?它是否有 blocking 版本的 getReadEvent() 方法?另外,我认为重点是让 OpenGL 线程调用release()(不管是什么),否则事情会中断?
标签: android game-engine onresume glsurfaceview onpause