Game thread AND render thread [OpenGL]?

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

Game thread AND render thread [OpenGL]?

Postby Skywhy » Tue Oct 20, 2009 8:37 pm

Basic question is: what is the correct way to do game loop on Android when using OpenGL? OpenGL "always" wants it's own thread, right? So basically, I'd need a thread to render stuff every loop and then I would need another thread to loop where I would read the input and update game logic?

I've done games using OpenGL on PC side but the whole android threading business confuses me at this point.

Generally my 2D game loop structure is roughly like this:
Code: Select all
while( gameRunning )
{
   updateInput();

   if( 20ms passed )  // just arbitary value, I don't update game logic EVERY loop
   {
      update lastUpdatedTime
      update gameLogic with the delta time
   }

   float t = calculate interpolation point from current time and lastUpdateTime
   renderEverything( t );  // with the interpolation point we get smooth looking movement on screen and yay :3
}


Now what would be the best way to go about doing this in Android? I'm guessing I'd have to use two different threads but.. how.. what? Feels confusing. I've gone through most of the examples, looked into many code examples on this site and others and generally they have one thread running the game loop and then they use Java canvas on the side to do drawing. I think I need another thread for my openGL and somehow need to wiggle stuff around between the openGL thread and the game logic thread (generally the interpolation point?). Or is the game loop built in a completely different manner on Android? Since I want it to move smoothly and look smoothly and this is where the rendering with the interpolation came into play.

But yeah, any advices how to build a proper game loop for a game on Android using openGL ?
Thank you.

// SkyWhy


EDIT #1: or if I missed and obvious link, thread or what not, post it. Something that would get me up to speed on how to go about getting a proper game looping structure working together with OpenGL. Does it require two threads and that stuff, like explained above.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Top

Postby nstegg » Wed Oct 21, 2009 6:40 pm

How I have mine set up, is let the gl thread do its thing, and render itself as fast as possible. In a separate "game thread", I call the logic updates on all of my sprites and whatnot in a similar fashion as your example code, locked to a certain FPS.

Now, depending on how you have your game structured, you would have to have your gl thread have a reference to all of the sprites for rendering, and the same for the updating thread for logic. This is how I have seen it done, as well as what has worked well for myself. That said, I believe you could disable the opengl auto rendering, and manually request renders, which would allow you to call both from the same thread (I don't do it this way).

In the end, you would have the gl thread, your updating thread, and then the UI thread all running (you are only having to set up the updating thread). Of course then you have to deal with handling lifecycle in regards to your thread as well, for pausing and resuming etc.

I hope this helps (let me know if you need more specific code examples).

-Nick
nstegg
Freshman
Freshman
 
Posts: 6
Joined: Fri Oct 02, 2009 11:56 pm

Postby Skywhy » Thu Oct 22, 2009 11:21 pm

Source examples would be great. I mean I've been looking at the Rokon 2D engine and seriously, all the implementations of opengl in any form (not just Rokon2D) are so .. well they feel really messed up. Not saying that there is anything wrong with Rokon2D, I think it's a great example piece of open source software.

But to me it feels like there is no proper distinction between logic updates (where you update stuff like all your entities(enemies, player), apply physics and suchs) and render.

To me it looks REALLY strange. I'm used to have my entities in a let's say List which I then call in update function (in logic update loop) that calls all of the entities and their own update function and same happens in render. I call the entities from the list but this time with their render functions.

logic loop:
Code: Select all
iterate entity list
   entity.update( deltaTime );


render loop:
Code: Select all
iterate entity list
   entity.render( interpolation point t );


of course there is more to it too but seriously, all the examples and tutorials I've found on this matter seem to be lacking. So I'm definitely open for a proper implementation of logic loop that goes through the entities and updates all the game logic and the entities and in render just calls them to render themselves. Seems like there is no clear distinction between visualisation component and world component of the game in any of these.

But hey, definitely, if you have any code examples, please, do share.

Cheers.

// SkyWhy

EDIT #1: so I guess my problem is I cannot figure out where everything SHOULD be on Android and where it makes the most sense. I'm so confused with this. I just want a simple looping structure where from I could call openGL and my update functions as quickly as possible without actually locking the device or doing anything stupid.

EDIT #2: Probably the stupidest idea of them all just hit me, could I have a openGL thread running and basically just using that thread for everything? Sloppy example follows:
Code: Select all
      // Loop until asked to quit
      while (!_gameRunning) {
         // update GAME logic
                        update(); // calling of entities, applying of physics etc.

         // Draw a single frame here...
                        drawFrame(gl); // render function to call all entities to render their sprites or what not to screen on given point. makes little to no sense?
         egl.eglSwapBuffers(display, surface);
         
         if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
            Context c = _view.getContext();
            
            if (c instanceof Activity) {
               ((Activity) c).finish();
            }
         }
      }


Naturally before the loop I'd initialise all openGL related stuff and after it free everything I've been using. But ... is this a completely wrong way to do it, or could I possibly go about doing it this way? I'm seriously hitting blanks here. Because I don't want to start developing my game before I know I'm doing it the "right way", I don't want to f up my final year project just for the fact that I don't understand how Android works or how it's done on Android properly and in the end realise that I've been doing it the wrong way all the time.

I went already through one book about Android development but it really didn't clear up this matter for me. It gave me really good points on how to go about things on Android but this is seriously still on the dark side.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby nstegg » Fri Oct 23, 2009 5:42 pm

If I am understanding you correctly (putting the logic updates in with the gl rendering thread), I would have to say to avoid that. The rendering thread needs to deal with pretty much just the rendering and little to no calculations and whatnot to get the best performance. Once you start doing extra stuff with the rendering, your fps will start to suffer. The above is assuming that you were using the actual gl rendering thread as is though, and not your own.

Here is how I have mine currently organized (I seem to keep re-working it though >< ):

The GameMain class sets up my view
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class GameMain extends Activity
  2. {
  3.         private GameView gameView=null;
  4.        
  5.     //--------------------------------------------
  6.     public void onCreate(Bundle savedInstanceState)
  7.     {
  8.         super.onCreate(savedInstanceState);
  9.         //Other stuff...
  10.         //...
  11.         //...
  12.            
  13.         //Setting up my GameView
  14.         gameView = new GameView(this);      
  15.            gameView.enableSplashScreen(R.drawable.logo, 4000, true);          
  16.         gameView.setTransition(new FadingTransition(R.drawable.blank, GameView.WIDTH,GameView.HEIGHT, 0,0,0));                
  17.      
  18.         //Starting
  19.         setContentView(gameView);  
  20.         gameView.startGame();
  21.     }//-------------------------------------------
  22.    
  23.     //Handle Input, other stuff...
  24.  
Parsed in 0.034 seconds, using GeSHi 1.0.8.4



My GameView class creates/manages my updating thread, sets the renderer, and other stuff
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class GameView extends GLSurfaceView
  2. {
  3.         //Other variables for sound/input/texture etc
  4.      //...
  5.      //...
  6.        
  7.         private GameRenderer renderer;//Game's Renderer
  8.         private GameUpdater updater;//Game's Updater   
  9.        
  10.         private Screen screens[]=null;
  11.         private int numScreens;  
  12.  
  13.         //-------------------------------------------- 
  14.         public GameView(Context context)
  15.         {//CONSTRUCTOR
  16.                 super(context);                
  17.                                        
  18.                 //Initialize Game attributes   
  19.           //...
  20.           //...
  21.                
  22.           renderer = new GameRenderer();        
  23.           renderer.addListener(new GameListener());
  24.        
  25.           updater = new GameUpdater(inputHandler);
  26.           updater.pauseThread();//Initially paused
  27.    
  28.         }//END CONSTRUCTOR
  29.         //--------------------------------------------
Parsed in 0.038 seconds, using GeSHi 1.0.8.4


The GameUpdater class handles game logic updates
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class GameUpdater implements Runnable
  2. {      
  3.     private final long period = 1000/30;//FPS
  4.     private Thread gThread = null;
  5.     private Screen screens[] = null;  
  6.     private int numScreens;
  7.     //timing variables...
  8.     //...
  9.  
  10.  
  11.     //-------------------------------------------
  12.     /**Updating the logic of the game.*/
  13.     private void doLogic()
  14.     {  
  15.         screens[currentScreen].update();                        
  16.     }//-------------------------------------------
  17.  
  18.     //---------------------------------------------    
  19.     public void run()//RUN
  20.     {  
  21.         //timing stuff
  22.        
  23.         while(running)
  24.         {
  25.                 if(!paused)doLogic();//Game Logic              
  26.                 //timing stuff / sleep thread (fps set to period)
  27.           //...
  28.                
  29.         }      
  30.     }//END RUN
  31.     //---------------------------------------------
Parsed in 0.036 seconds, using GeSHi 1.0.8.4



The GameRenderer handles initial texture loading, and renders sprites
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class GameRenderer implements GLSurfaceView.Renderer
  2. {
  3.     private ArrayList<RenderingGroup> renderables;//Sprite groups (only render 1 group at a time by ID)
  4.     private int numGroups;//Number of groups
  5.     private int currentGroup;//Current group to render  
  6.     //other stuff...
  7.     //...
  8.  
  9.  
  10.    //---------------------------------------------
  11.     public void onDrawFrame(GL10 gl)
  12.     {  
  13.         //gl stuff...  
  14.            
  15.         if(loadTextures)
  16.         {//Load any textures added before rendering anything else
  17.                 splashScreen.render(gl);//Render SplashScreen
  18.                 //load textures...
  19.           //...
  20.         }
  21.         else
  22.         {      
  23.                 renderables.get(currentGroup).render(gl);    
  24.         }
  25.     }//--------------------------------------------
Parsed in 0.037 seconds, using GeSHi 1.0.8.4


Obviously, there is much left out in the above bits, but it should give an basic idea of how I do it in mine. The idea is that the updating thread is separate from the rendering thread, and simply updates what needs to be updated, and the rendering thread renders what needs to be rendered. Sprites are added to the renderer, and rendered in order of layer, sorted by texture used, and only for the currently displayed screen. Likewise, the updater updates the currently set screen (all of the sprites / managers). Once you strip away all of the screens/managers/groups, all you really have is arrays of sprites that are updated/rendered when needed.

I hope this helps! Once again, this isn't too specific, so I apologize if it does not answer any questions.

-Nick
nstegg
Freshman
Freshman
 
Posts: 6
Joined: Fri Oct 02, 2009 11:56 pm

Postby Skywhy » Sun Oct 25, 2009 2:04 pm

Thanks for the help Nick, there are still few things that bug my mind in your example.

So when you call:
Code: Select all
gameView.starGame();

I'm guessing you are just doing a thread.start() on the GameUpdater object in gameView? I'm sorry if these questions are blindinly obvious but I kind of want to be sure :) So then the GameUpdater is running in it's own thread and we get the run()-method to be called every time slice the tread gets. Roughly the right idea? So the thread is in some what working order and is running on it's own.

But what about the rendering then? How do we call that? It's not implementing any Threads or anything, so what is the deal here? How does it get called? And what does the GameListener()-object do that is passed to the Renderer? I should be sorted pretty much once I get this thing up and running.

Thanks for all the help you have already provided.


// SkyWhy
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby nstegg » Sun Oct 25, 2009 6:47 pm

It would appear that this is what the startGame method is doing (probably what it shooould be doing >< ), but it does not actually start the updater thread. At the moment, I have the updater thread re-create and start a new thread on each onResume(), and kill the thread on the onPause(). The thread is initially set to paused when the app is first launched, to avoid any problems when setting everything up. I have bounced back and forth between "pausing" the thread vs allowing it to exit when the onPause is called, this is just where its currently at.

Now, what the the startGame method is actually doing, is some other things, such as registering all of the sprites to the renderer, clickable sprites to the input handler, etc (just how I have it set up at the moment). Lastly, the startGame method is calling the view's setRenderer() method.

If you look at the documentation for setRenderer(), you see that this is what gets the opengl thread going. As such, it is only called once, which is what I wanted the startGame() to represent. The rendering thread is automatically handled by opengl after this call, which will call the onDrawFrame() in the renderer as fast as it is able (~60 fps cap). So, after you call the setRenderer in your view, know that the onDrawFrame will begin to get called.

Heh, the addListener(new GameListener()) is just something I added in to handle event calls. The GameListener is just an event listener that I have been using throughout the program. In this case, I can use an event listener for my renderer to let the view know when certain things happen, such as all textures being loaded or whatnot. Likewise, my managers can use these to communicate with the view if need be.

Sorry for the confusion, I meant to filter out the all of the non-essentials but I guess I left in some of my method calls in my examples. Don't hesitate to ask any more questions, getting the app to correctly, pause, resume, render, and whatnot (without crashing!) is the hardest / must confusing part. Not to mention that there does seem to be a great deal of different ways to go about doing it, which makes it all the more confusing.

-Nick
nstegg
Freshman
Freshman
 
Posts: 6
Joined: Fri Oct 02, 2009 11:56 pm

Top

Postby Skywhy » Tue Oct 27, 2009 12:58 am

Thanks again for all the help Nick. Now I've got the updater thread going on solid, but problems arise with the setRenderer()-method call.

I call it in my GameView class but.. nothing, absolutely nothing happens. As far as the API documentation goes yes, it should start, but..? Any ideas where things are hitting the wall?

# EDIT #1:
Ah, sorry, it did seem to boot up the thread. My debugs just didn't show up in the LogCat because the update thread flooded the LogCat with it's output. Hmmh, seems like the openGL thread gets called max 60fps? Just wondering since seems like the actual update thread with simple run() to print "update thread" in it seems to be called a huge amount of times and every now and then the render thread flashes by with its "render thread" debug.

So am I correct thinking that the render thread gets called max 60fps and the update thread whilst not tied to OpenGL will be called at as many times as possible? Or am I completely shooting off with my thinking?

Now that I got two threads going on, the update and the render, can I start hassling around with the fact that I can go ahead and update everything game related in my updates run method and draw everything to their current positions in the opengl render thread started by setRenderer()? Or is there still something magical I need to take into account?


Cheers. :)


// SkyWhy
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby nstegg » Tue Oct 27, 2009 4:55 pm

Yes, the rendering thread will cap out at ~60 fps. That said, once you start rendering many sprites, expect that number to go down, and have to deal with endless optimizations! The update thread will indeed get called as fast as possible as is, which will of course need the timing in place to slow it down to the desired speed. One thing to keep in mind, is any synchronization that you may have to deal with, should you ever have to communicate between the rendering and updater threads (I just make sure my sprites have a distinct separation between rendering and updating). Sounds like you are good to go :)

-Nick
nstegg
Freshman
Freshman
 
Posts: 6
Joined: Fri Oct 02, 2009 11:56 pm

Data synchronization

Postby alvion » Wed Feb 10, 2010 11:26 pm

Hi nstegg, thanks for posting your game thread architecture. I have a question about data synchronization though. Since your sprites are shared by more than one thread, don't you need to synchronize access to them? Otherwise, you could get all kinds of issues when rendering partially updated sprites, not to mention accessing sprites that are destroyed mid-render. How do you handle this? Do you have per-sprite synchronization? Or is it just somehow not an issue for you?

I know that for PC and Console games, a common approach is for the update thread to generate a set of "snapshots" containing only the data needed to render the sprite to the render thread. That way, if a sprite is mutated or destroyed while the render thread is processing the data, it won't be an issue.
alvion
Freshman
Freshman
 
Posts: 4
Joined: Sat Nov 07, 2009 12:51 am
Location: San Francisco, CA

Postby zorro » Thu Feb 11, 2010 8:59 am

Hello. I came from PC OpenGL development, too. I read a lot about Android threading mechanisms, the render thread, the game logic thread, etc. But to keep it simple I decided for my first project to go with the 'single thread' approach. I do every thing in the rendering thread. In the rendering function i have something like: UpdateGame(); Render(gl); Flush(); so the whole thing is happening in the GL thread. I don't have to deal with synchronization, and the FPS may be lower than the 2 thread implementation, but not by much. And the question is: how is suppose to help me getting 2 GL frames for one game 'frame' when the two GL frames are identical? So that's why i decided (for now) to try a 'classic' approach. And in the end i got 30-50 FPS with lots of stuff on the screen, which conforts me. In the next game maybe I will try a two threads approach. The only thing that will get a benefit with the 2 threads approach is the use of VBO extension, which permits the computing and rendering to be done simultaneously. And of course we are all waiting for a dual core cpu phone.. :)
User avatar
zorro
Experienced Developer
Experienced Developer
 
Posts: 71
Joined: Mon Aug 10, 2009 3:11 pm
Location: Romania

Postby Skywhy » Thu Feb 11, 2010 3:41 pm

Everybody makes data synchronization sound like a black art. It really is not. Simplest way of probably doing it is a simple monitor pattern. There are many different ways of doing it but you should always start from the simplest, if it's not working for you, move onto the next one.

Pseudo-random-code-thrown-together-from-the-top-of-my-head: (roughly the way mine works)
Code: Select all
class World {
  private ArrayList<Entity> entityList;

  /** This method is called by Update thread. */
  public void update(int timeMs) {
     for( Entity e : entityList ) {
        synchronize(e) {
           e.update(timeMs);
           e.notifyAll();
        }
     }
  }

  /** This method is called by render thread */
  public void render(GL10 gl, int timeMs) {
     for( Entity e : entityList ) {
        synchronize(e) {
           e.render(gl, timeMs);
           e.notifyAll();
        }
     }
  }
}


That's roughly about it, now the access to entity data is synchronized. It's thrown together from the top of my head. Basically what is left to do is OpenGL initialisation, update thread initialisation. Obviously both render thread and update thread will have an reference to the World so they can access it's public methods.

@zorro I have absolutely no idea what you mean by: "how is suppose to help me getting 2 GL frames for one game 'frame' when the two GL frames are identical?". I'd suggest you drop the glFlush(); from your program. Behaviour is not guaranteed on all platforms.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby zorro » Thu Feb 11, 2010 4:05 pm

I'm not using glFlush(). I just put the 'flush' there to suggest the end of my loop (my mistake).
I was saying that by running the rendering and game update threads in parallel, if the game update thead is doing some heavy math tasks (for ex. physics) the rendering thead will loop faster and in the end for every game update 'frame' completed the rendering thread would render two 'frames'. But these 2 frames will be identical because they were computed using data from the previous game thread update loop. So the extra frames are no usefull at all, that's what I think..
User avatar
zorro
Experienced Developer
Experienced Developer
 
Posts: 71
Joined: Mon Aug 10, 2009 3:11 pm
Location: Romania

Postby Skywhy » Thu Feb 11, 2010 4:19 pm

Ah, now I understood, thank you.

I do agree, it's "useless" if nothing updated BUT that's where communication and data synchronisation comes into play. If the thread rendering everything gets a message that everything is not ready / fetches a message / flag, what ever you want to call it, and realises it doesn't have to render it can wait until there is something "new" to render.

Plus even if you rendered the "useless" frame, the user won't be able to tell the difference. To the user everything will be going as it's supposed to be.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Re: Game thread AND render thread [OpenGL]?

Postby yaolin170 » Thu Jul 15, 2010 11:40 am

Hi Everyone,

I am involved in an issue ,also about the thread problem .
I am developing 3d game on android platform .obviously, the game include 2d part (such as all menus and all UI and so on )and 3d part .but i don't know how to render them in a good structure .

For the 3d sprites ,as we know .I render them by calling the function as below:
class GameRenderer implements GLSurfaceView.Renderer {
public void onDrawFrame(GL10 gl) {
draw3D();
}
}

For the 2d parts, I create a new thread ,and draw all the 2d factors such as bitmap ,text and so on in these codes:
while (_isRunning())
{
Canvas c = null;
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder)
{
// means draw all 2d things on the "android.graphics.Canvas"
g._setCanvas(c);
draw2D(g);
}
................
}


so in my code ,there are two Activity classes ,and two SurfaceView classes.
one is "class GameView extends SurfaceView implements SurfaceHolder.Callback {}" ,it is for 2D
and the other is "class GameGLSurfaceView extends GLSurfaceView {}" ,it is for 3D.

i know the structure of mine is not good .
the problem of mine is :
1) i don't know how to link them ,or how to exchange them --the two SurfaceView
2) i don't know how to draw 2d and 3d things at the same time .
3) i use the startActivity function .for example ,when i am in main menu in the 2D part,in the new created thread (the logics of 2d is put in the new thread),i click the option "New Game" and I want to go to 3D scene of the game . I enter into the 3DActivity ,in the function "void onCreate(Bundle savedInstanceState) {}" i enter into the "GameGLSurfaceView(Context context) {}" ,then i enter into the "class GameRenderer ",generally speaking ,it should go to the function
"onSurfaceCreated(GL10 gl, EGLConfig config) {}" .but unfortunatly ,it doesn't go into it .and the debug mode crashed ,i don't know why , i think maybe it has some matter with the new thread i created.

if there are something i don't tell clearly ,please let me know ..
thanks for your any help in advance !

Allen
No Gods ,No Kings,Only Man!
yaolin170
Junior Developer
Junior Developer
 
Posts: 10
Joined: Fri Oct 23, 2009 7:21 am

Re: Game thread AND render thread [OpenGL]?

Postby Skywhy » Thu Jul 15, 2010 11:58 am

set Opengl ES camera stuff, Draw 3D stuff, switch opengl to use 2D projection and render ui elements. Rinse and repeat. And not to sound like a dick, but throw all the canvas poo away and just use opengl for everything. You are doing it so backwards that it makes no sense.

Just use OpenGL ES to do everything.

Things you need to figure out:
- Correct projection for 3D stuff (which I'm assuming you already have if you render 3D stuff correctly)
- Render 3D models (Again, assuming it already works)
- Telling opengl es to use 2d projection (millions of posts about it)
- Rendering all 2D stuff (UI) in screen space coordinates

And there you go.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Top
Next

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 8 guests