我在c++游戏上工作,该游戏在GLSurfaceView的视频线程中运行(游戏的循环是GLSurfaceView的循环,因为它在continuos模式下运行(。我在如何正确处理活动方面遇到问题。暂停/onResume和本机暂停我的游戏。在本机中,我发布了opengl资源和各种大数据。我没有nativeResult,因为当我调用GLSurfaceView.onResume((时,这是由Android处理的,它再次调用方法onSurfaceCreated/onSurfaceChanged,我在其中再次分配资源。
以下是我现在的做法:
OnPause
java中的活动处理onPause并运行glSurfaceView:的自定义nativePause方法
@Override
protected void onPause() {
super.onPause();
glSurfaceView.nativePause();
}
nativePause向游戏的视频循环发送异步请求。处理视频内循环并释放各种资源。接下来,向主线程发送另一条消息,其中包含nativePause已完成的信息,我执行GLSurfaceView.onPause((,这将停止视频线程。
on恢复
该方法实现简单,它只使用onResume((启动surfaceview的视频线程
@Override
protected void onResume() {
super.onResume();
glSurfaceView.onResume();
}
但问题是,onPause对视频线程和主线程进行异步调用。Activity.onSume通常在整个暂停机制完成之前就被调用,然后崩溃或挂起。如果游戏在视频线程中运行,我应该如何正确处理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中的Native 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();
}
第2版:
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);
}
};
小心这个易失性的技巧。在很多情况下,它不会做你认为它会做的事情。如果到目前为止效果良好,那可能是运气使然。
由于InputQueue
类实际上并不适合这样做,我将向您展示如何使用条件变量(未测试的代码(来解决问题:
#include <pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
bool released = false;
...
pthread_cond_init(&cond, NULL); //TODO: check return value
pthread_mutex_init(&mutex, NULL); //TODO: check return value
...
void nativePause() {
InputEvent *event = inputQueue.getWriteEvent();
event->type = InputEvent::PAUSE;
inputQueue.incWriteIndex();
//Wait for the OpenGL thread to accomplish the release():
pthread_mutex_lock(&mutex);
while(!released) {
pthread_cond_wait(&cond, &mutex); //Expected to always return 0.
}
pthread_mutex_unlock(&mutex);
}
void onDrawFrame() {
...
if (event) {
inputQueue.incReadIndex();
....
if (event->type == InputEvent::PAUSE) {
release();
pthread_mutex_lock(&mutex);
released = true;
pthread_cond_broadcast(&cond); //Notifies the nativePause() thread, which is supposed to be blocking in the condition loop, at this point.
pthread_mutex_unlock(&mutex);
return;
}
}
...
}
...
void nativeCleanup()
{
pthread_cond_destroy(&cond); //Expected to return 0.
pthread_mutex_destroy(&mutex); //Expected to return 0.
}
至少,这应该奏效。代码假定OpenGL线程保证在onPause()
返回之前一直存在。我想这是真的;我真的不记得了。