I wanted to write some simple game in android using opengl es but immediately ran into trouble with the main game loop. As I read here: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html the app calls public void onDrawFrame(GL10 gl) every time it needs to redraw the surface. Or smth like that. My problem was - how to create an update loop that is independent of draw calls. I mean - it can't work like that, I can't update the game logic only when the device (app?) wants to redraw the surface (or am I wrong?).
After some googling I came to a conclusion that I have to create another thread for update loop. But then I had another problem - with one thread taking care of drawing and another one taking care of updating the game logic I didn't know how to make them cooperate. First, they were two separate classes (at least in my implementation) so they couldn't use the same game variables and objects (sprites, timers, different variables, counters and so on... pretty much everything these two classes needed to do their jobs). Now I think I could somehow pack them both into one class. But - second, I needed to synchronize the two threads somehow.
Finally, I came out with this general idea:
3 classes:
public class MyRenderer implements GLSurfaceView.Renderer with onSurfaceCreated() method taking care of drawing
public class UpdateThread implements Runnable with run() and update() methods. run() was calling update() method exactly 60 times a second (I wanted a fixed step loop)
public class SpritesHolder used as a container for all the game objects/variables/stuff (like sprites, timers, state variables and so on...) with all the fields public.
So basically the SpritesHolder class was a box holding all the needed variables in one place, so MyRenderer and UpdateThread classes could access it and use it.
As for synchronization - I just did smth like this:
public void update(float delta)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
and:
public void onDrawFrame(GL10 gl)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
so that both threads didn't use the spritesHolder at the same time. So updates were done 60 times per second and drawing took place whenever app (device?) needed.
A lot of talking, sorry, I've almost finished writing this post. ;) So anyway - this (described above) works and I even did write some game based on this 'template' but I think my ideas might be crazy and one can desing it all a whole lot better. I'd be very grateful for all comments and advices.
Your solution probably will work, though it might be suboptimal for performance. If you think about it the render thread and the update thread don't really need to be 100% exclusive.
I recently spent a while thinking about this for my game, and this is what I ended up coming up with (not necessarily better, but just something to think about):
For every renderable object, I have an object owned by the update thread, and another object owned by the rendering thread that is just a plain container that contains instructions for how to draw an object (model matrix, uniform values, meshID, etc). I run through the update thread computing all the final positions and values for my renderable objects, and then I synchronize for a small window where I pass any values that changed during that frame to the objects in the renderable thread. Then as soon as the new information has passed, the frame rendering begins while the next update frame runs simultaneously. Because there's only a small exclusion window it allows the update and draw threads to run simultaneously most of the time.
I didn't use this with OpenGL yet, but UpdateThread should be a TimerTask.
In you activity launch it with
new Timer().schedule(new UpdateThread(view), 0, 15); //where view is your view, and 15 is the wait time
in your TimerTask call the view with a Handler. e.g (in your view class)
Handler refreshHandler = new Handler() {
public void handleMessage(Message msg) {
//Handle it; e.g. for canvas invalidate()
}};
In your UpdateThread run method do this:
view.refreshHandler.sendMessage(new Message());
Now it is independent of your gameloop. Furthermore your gameloop should not be in the MainActivity but in a Thread (unidirectional OO).
Related
I have a game loop which is constantly being called to update the game. Inside that loop is the following code:
mySurfaceView.post(new Runnable() {
public void run() {
myView.setTranslationX(myCam.getX());
myView.setTranslationY(myCam.getY());
}
});
I've been told that putting the "new" keyword in my game loops is usually not a good idea because memory is constantly being allocated to new objects. However this is an anonymous inner class so I'm not sure if the same applies here. Would this code cause performance issues? And if so, then how would I go about solving them? I use this code to make my the screen be oriented around my player when he moves.
One approach would be to send a message to a Handler on the UI thread, rather than posting a Runnable. This is easiest if your translation X/Y values are integers.
For an example, see the way ActivityHandler is used in the "record GL app" activity in Grafika. The UI thread creates a new Handler and passes it to the renderer thread, which sends messages to it. handleUpdateFps() is a good example, as it's passing a pair of integers to the UI thread.
If you can't pass the values as fixed-point, you have to pass them through an Object, and things start to get complicated. Overall this approach is more involved than simply posting a Runnable.
(A better approach would be to adjust your coordinates internally, having a notion of "world space" vs. "screen space", and not mess with the View's values. But looking at your other questions, you tried that approach and were not successful.)
Talking in context of a game based on openGL renderer :
Lets assume there are two threads :
that updates the gameLogic and physics etc. for the in game objects
that makes openGL draw calls for each game object based on data in the game objects (that thread 1 keeps updating)
Unless you have two copies of each game object in the current state of the game you'll have to pause Thread 1 while Thread 2 makes the draw calls otherwise the game objects will get updated in the middle of a draw call for that object ! which is undesirable!
but stopping thread 1 to safely make draw calls from thread 2 kills the whole purpose of multithreading/cocurrency
Is there a better approach for this other than using hundreds or thousands or sync objects/fences so that the multicore architecture can be exploited for performance?
I know I can still use multiThreading for loading texture and compiling shaders for the objects which are yet to be the part of the current game state but how do I do it for the active/visible objects without causing conflict with draw and update?
The usual approach is that the simulation thread after completing a game step commits the state into an intermediary buffer and then signals the renderer thread. Since OpenGL executes asynchronously the render thread should complete rather quickly, thereby releasing the intermediary buffer for the next state.
You shouldn't render directly from the game state anyway, since what the renderer needs to do its works and what the simulation produces not always are the same things. So some mapping may be necessary anyway.
This is quite a general question you're asking. If you ask 10 different people, you'll probably get 10 different answers. In the past I implemented something similar, and here's what I did (after a long series of optimisation cycles).
Your model-update loop which runs on a background thread should look something like this:
while(true)
{
updateAllModels()
}
As you said, this will cause an issue when the GL thread kicks in, since it may very well render a view based on a model which is half way through being rendered, which can cause UI glitches at the best case.
The straight-forward way for dealing with this would be synchronising the update:
while (true)
{
synchronized(...)
{
updateAllModels();
}
}
Where the object you synchronize with here is the same object you'll use to synchronize the drawing method.
Now we have an improved method which won't cause glitches in the UI, but the overall rendering will probably take a very severe performance hit, since all rendering needs to wait until all model updates are finished, or vise versa - the models update will need to wait until all drawing is finished.
Now, lets think for a moment - what do we really need to be synchronizing?
In my app (a space game), when updating the models, I needed to calculate vectors, check for collisions and update all the object's positions, rotations, scale, etc.
Out of all these things, the only things the view cares about is the position, rotation, scale and a few other small considerations which the UI needs to know in order to correctly render the game world. The rendering process doesn't care about a game object's vector, the AI code, collision tests, etc. Considering this, I altered my update code to look something like this:
while (true)
{
synchronized(...)
{
updateVisibleChanges(); // sets all visible changes - positions, rotations, etc
}
updateInvisibleChanges(); // alters vectors, AI calculations, collision tests, etc
}
Same as before, we're synchronising the update and the draw methods, but this time, the critical section is much smaller than before. Essentially, the only things which should be set in the updateVisibleChanges method are things which pertain to the position, rotation, scale, etc of the objects which should be rendered. All other calculations (which are usually the most exhaustive ones) are performed afterwards, and do not stop the rendering from occurring.
An added bonus from this method - when you're performing your invisible changes, you can be sure that all objects are in the position they need to be (which is very useful for accurate collision tests). For example, in the method before the last one, object A moves, then object A tests a collision against object B which hasn't moved yet. It is possible that had object B moved before object A tested a collision, there would be a different result.
Of course, the last example I showed isn't perfect - you will still need to hang the rendering method and/or the updateVisible method to avoid clashes, but I fear that this will always be a problem, and the key is minimizing the amount of work you're doing in either thread sensitive method.
Hope this helps :)
Hi Android Developers,
What is the best way to interrupt a current rendering phase of GLSurfaceView and start a new one when mode is equal to "Render_when_dirty"? I artificially stop rendering in "onDraw" method by checking a flag and returning from actual rendering method which is called in "onDraw" method; then, in main thread's context i call "requestRender()" to refresh the scene. However, due to a reason that i am not aware of, some of the intermediary old frames are displayed for a very very short period of time(on the other hand, they endure for so long period of time that users can realize the transition); before actual scene is rendered by opengl es 2.x engine. It doesn't affect anything at all; but troublesome to be fixed. What do you suggest?
P.S. Throwing InterruptedException within onDraw method is useless due to the destruction of actual rendering thread of GLSurfaveView.
Kind Regards.
When you say some of the old frames are drawn - do you mean part of the frame that is drawn is old or multiple calls of onDraw() still lead to some of the old information being shown on the display.
There are a few things I can see happening here. If you have a onDraw() like this:
onDrawFrame(){
... stuff ...
if (stateVariableSet)
return;
... stuff ...
my understanding is that when the function is done being run, that the back/front buffer get swapped and drawn. One thing that could be happening here is that you see a few calls of onDrawFrame() being rendered while you try to update the state/State variable.
On the other hand, if you have something like this:
onDrawFrame(){
... stuff..
semaphore.acquire(); // lock the thread waiting for the state to update
... stuff ...
then the things that have been drawn before the lock will be stale (for that frame only though - at least that's what I'd anticipate).
Also are you running on a multi-core system?
I've been studying and making little games for a while, and I have decided lately that I would try to develop games for Android.
For me, jumping from native C++ code to Android Java wasn't that hard, but it gives me headaches to think about how could I maintain the logic separate from the rendering.
I've been reading around here and on other sites that:
It is better to not create another thread for it, just because
Android will for sure have no problems for processing.
Meaning the code would be something like this:
public void onDrawFrame(GL10 gl) {
doLogicCalculations();
clearScreen();
drawSprites();
}
But I'm not sure if that would be the best approach. Since I don't think I like how it will look like if I put my logic inside the GLRenderer::onDrawFrame method. As far as I know, this method is meant to just draw, and I may slow down the frames if I put logic there. Not to mention that it hurts the concepts of POO in my understanding.
I think that using threads might be the way, this is how I was planning:
Main Activity:
public void onCreate(Bundle savedInstanceState) {
//set fullscreen, etc
GLSurfaceView view = new GLSurfaceView(this);
//Configure view
GameManager game = new GameManager();
game.start(context, view);
setContentView(view);
}
GameManager:
OpenGLRenderer renderer;
Boolean running;
public void start(Context context, GLSurfaceView view) {
this.renderer = new OpenGLRenderer(context);
view.setRenderer(this.renderer);
//create Texturelib, create sound system...
running = true;
//create a thread to run GameManager::update()
}
public void update(){
while(running){
//update game logic here
//put, edit and remove sprites from renderer list
//set running to false to quit game
}
}
and finally, OpenGLRenderer:
ListOrMap toDraw;
public void onDrawFrame(GL10 gl) {
for(sprite i : toDraw)
{
i.draw();
}
}
This is a rough idea, not fully complete.
This pattern would keep it all separated and would look a little better, but is it the best for performance?
As long as I researched, most examples of threaded games use canvas or surfaceview, those won't fit my case, because I'm using OpenGLES.
So here are my questions:
Which is the best way to separate my
game logic from the rendering when using OpenGLES? Threading my
application? Put the logic in a separate method and just call it from
the draw method?
So I think there are two ways you can go here.
Do all updates from onDrawFrame(): This is similar to using GLUT, and Android will call this function as often as possible. (Turn that off with setRenderMode(RENDERMODE_WHEN_DIRTY).) This function gets called on it own thread (not the UI thread) and it means you call your logic update here. Your initial issue was that this seems a little messy, and I agree, but only because the function is named onDrawFrame(). If it was called onUpdateScene(), then updating the logic would fit this model well. But it's not the worse thing in the world, it was designed this way, and people do it.
Give logic its own thread: This is more complicated since now you're dealing with three threads: the UI thread for input, the render thread onDrawFrame() for drawing stuff, and the logic thread for continuously working with both input and rendering data. Use this if you need to have a really accurate model of what's happening even if your framerate is dropping (for example, precise collision response). This may be conceptually a little cleaner, but not practically cleaner.
I would recommend #1. You really don't need #2. If you do, you can add it later I guess, but most people are just using the first option because the hardware is fast enough so you don't have to design around it.
Keep your design as simple as possible :)
The standard (and maybe the best) approach is following:
public void update(){
while(running){
updateAll();
renderAll();
}
}
I would pay attention on some moments:
you need to call sequently update and render methods, avoid calling update twice a time
if you prefer multithreading (I don't), design your methods so update writes data and render reads only
keep in mind that OpenGL has it's own "thread", so when you call GL function it only sends some command to OpenGL (except glFlush() - it completes all commands)
I am not fully understanding what the synchronization block is doing nor why it is necessary.
Can someone explain in a "synchronizing for dummies" kind of way?
In a book I am reading, the author tells me "The synchronization is necessary, since the members we manipulate within the
synchronized block could be manipulated in the onPause() method on the UI thread."
He creates an Object named stateChanged and instantiates it as a new object.
Then, in the synchronization block he uses the stateChanged object as the argument.
This whole thing is throwing me off and I do not like to move on until I have a pretty good understanding of what is going on.
The classic example is: Imagine you have two threads of operation, and both of them reference the same method:
public void addToGlobalVar(int y) {
int x = globalVar; //what if a thread stops right after this line?
x += y;
globalVar = y;
}
where globalVar is some other predefined number that this method can interact with and set. Lets say globalVar is 50.
Threads get computing time on a somewhat arbitrary basis, so you never fully know the precise nanosecond one stops and the other gets CPU time.
In this example, if you launched an AsyncTask in addition to the UI thread, and both at some point use addToGlobalVar(10), what can happen is that one thread might be interrupted at line 2 of that code block. If the other thread goes through while that one is sleeping, it will successfully set globalVar to 60. But when the other one wakes up, it still thinks x = 50, and its going to then set it to 60. So in essence you just made 50+10+10 = 60. Hopefully you can see how this becomes a problem.
You can fix this simple example by making the calculation atomic (skip declaring x, 1 line, all calcs done) or if the logic wasn't able to be condensed to 1 line, you make a block of code atomic by using synchronized.
The book to read is Java Concurrency in Practice.
You should really just segregate this idea from Android, although your code is going to be running on Dalvik this is a Java concept. Not an Android one.
The synchronized block takes an object as a parameter, any object, and when flow enters the body of the synchronized block, any other thread that runs in to a synchronized block with the same instance (object) as the parameter has to wait for the previous one to complete. That's a very basic description.
This is an entire sub-field of computer science and without serious study you will probably not understand it.
You have to fully understand it before you use it. It is standard android synchronization using object-oriented monitors. You have to understand it to write multi-threaded programs, however it is somehow dated (better use java.util.concurrent for anything thread/synchronisation related instead).
Anyhow - you need to know what it is about - read the related java tutorial part:
http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html