5
\$\begingroup\$

I first created a game on the iPhone and I'm now porting it to Android. I wrote most of the code in C++, but when it came to porting it wasn't so easy. The Android's way is to have two threads, one for rendering and one for updating - this due to some devices blocking when updating the hardware - while the iPhone's way is to have one thread to do it all.

My problem is that I am coming from the iPhone. When I transition, say from the Menu to the Game, I would stop the Animation (Rendering) and load up the next Manager (the Menu has a Manager and so has the Game). I could implement the same thing on Android, but I have noticed on game ports like Quake, don't do this - as far as I can tell.

What I want is someone to explain how a game like Quake can transition from the menu to the game? Does it stop rendering, load the game stuff and then start rendering again, like what I did on the iPhone? Does it load the game stuff while still rendering the menu?

Interestingly, when I did try to load a Renderer class while renderering I would get a dequeuing buffer error - which I believe to be OpenGL ES. Was I just doing something wrong or is it possible to load textures and buffers, while it's rendering?

Examples would be appreciated.

\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

Rendering on a separate thread is a common idiom.

To quickly and directly answer your question about "Was I just doing something wrong or is it possible to load textures and buffers, while it's rendering?" - OpenGL ES has a rendering context bound to one thread and calling any OpenGL ES functions from any other thread is illegal. More on that in a bit.

Quake is a single threaded program, and written for DOS originally. Its code is fairly specific to the game, but basically the menus are built-in and simple rendered on top of the 3D graphics (if any). It has been a while since I've read through the source, but conceptually, the game loop is this:

loop {

update_game();

if(menu_up)
    draw_menu();

draw_world();

}

I think rendering on a different thread is generally good because it forces you to separate the app's logic from the presentation layer from the actual rendering code, and even on the iPhone, I suggest you use it (new iPad is dual core!). Additionally, you abstract the drawing interface from rendering API.

It presents some challenges and in your case, the challenge is synchronizing the logic with the presentation. If you aren't writing a full-out game engine that is meant to be reused by both, then sharing the menu state with the renderer thread would be the most direct way. Basically something like this:

renderer_thread_loop() {


lock( sharedState.mutex )
if(sharedState.menuUp == true) {
   draw_menu(sharedState.menuState);
}
unlock( sharedState.mutex )

render_game();
}

There are a lot of synchronization issues here, tread carefully! You can't update information the renderer is rendering!

A less direct but more elegant way would be to submit stuff to the renderer to do. Each frame, some presentation layer code would queue up tasks for the renderer to do. At the end of the queue might be a "swap buffers" message that tells the renderer to swap buffers. In this way, the renderer runs on a separate thread but acts similar to directly calling functions like glDrawArrays(). Normally, the logic updates stuff, the presentation layer decides what to draw, and the renderer draws it.

A more full example would be this:

logic() {
  respond_to_input(); //move character, interact with menus
  update_game(); //physics, AI, etc.
}

presentation() {

    queueBeginFrame();

    if(inMenu) {
        queueDraw(menu);
    }


    queueEndFrame();
}


renderer() {

    while(game_not_exited) {
    if(queue.empty() == false)
    {
       work = queue.fetch();

       doWork(work); //do something with the request
    }

}
\$\endgroup\$
4
  • \$\begingroup\$ Are you suggesting then that I should be able to load textures, buffers, at any point as long it is on OpenGL ES thread? It's more the memory allocating stuff I am having problems with when it comes to rendering. \$\endgroup\$
    – NebulaFox
    Commented Mar 8, 2011 at 2:26
  • \$\begingroup\$ The points at which you are able to load resources (e.g. glGenTextures()) are well defined, specifically after successfully calling eglMakeCurrent(). Since your render thread must create resources and the other threads define what must be loaded, you have to use some kind of communication. Generally, resource handles are used to reference these, for example: handle = loadTexture("file.png"); //signal renderer to load a texture. queueState(SET_TEXTURE, handle); queueDraw(model); \$\endgroup\$
    – PatrickB
    Commented Mar 8, 2011 at 2:47
  • \$\begingroup\$ If your question is "when can I, on the render thread, define new resources", I'd say check the manpages for the OpenGL ES function. link Also, use glGetError() to find out what the problem is, don't guess! \$\endgroup\$
    – PatrickB
    Commented Mar 8, 2011 at 2:58
  • \$\begingroup\$ It's more about how then when, and I think you answered that in your first comment - the handlers. I am just making sure that I don't have to stop or interrupt the render thread. And that it is okay to load resources while rendering where it's to be expected, like after tapping a button. \$\endgroup\$
    – NebulaFox
    Commented Mar 8, 2011 at 3:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .