What is different between this:
queueEvent(new Runnable(){
#Override
public void run() {
mRenderer.method();
}});
And this:
mRenderer.method();
And what is better for OpenGL FPS?
GLSurfaceView creates a separate rendering thread. In OpenGL, you need a current context for making any OpenGL calls. The "current context" state is per thread. GLSurfaceView creates an OpenGL context for you, and makes it current for any of the GLSurfaceView.Renderer overrides you implement. So as long as you make OpenGL calls in those methods, you don't have to worry about any of that, it just works like pure magic (well, it's not really magic, but hides a lot of complexity).
Based on this, you can't make OpenGL calls from the UI thread without jumping through hoops. So simply calling a method on the Renderer in something that is e.g. triggered by user input, and then making OpenGL calls in that method, will fail. Beyond that, even if you don't make OpenGL calls in the method, you have to worry about thread safety if the method accesses/modifies member variables of the Renderer that are also used by the rendering thread.
Using queueEvent() provides a convenient way of executing a method in the rendering thread. So you don't have to worry about thread safety of Renderer member variables, because all access will happen in the rendering thread.
I believe you might also be able to make OpenGL calls in that method if you submit it through queueEvent(). But I'm not totally sure if the OpenGL context is always current in the rendering thread, or if that's only guaranteed while the Renderer method overrides are called. It's much more typically to just change state in the Renderer in response to user input, and then use that new state in your override of Renderer.onDrawFrame().
Related
I'm trying to execute some OpenGL commands for my GLSurfaceView from my main activity. As the OpenGL renderer works in its own thread, I have to use queueEvent, as far as I understand.
I'm calling queueEvent with the following code in my GLSurfaceView:
queueEvent(new Runnable(){
#Override
public void run() {
renderer.doSomething(data); //executes some OpenGL commands
requestRender();
}});
The doSomething() method binds a texture and compiles shaders.
This does not work. glCreateProgram returns 0, which happens for example when a GL command is executed outside of the GL thread. Exactly the same code also works fine if I execute it from within my renderer. So it seems that the commands I execute using queueEvent are not executed within the GL context, but are executed in the wrong thread.
Is my understanding that calling queueEvent is sufficient to execute code inside the GL thread wrong? Is there anything else I have to do, or any mistake in how I call it now?
It did some experimenting and it seems that in some cases queueEvent will execute the Runnable before onSurfaceCreated is actually called, though still on the GL thread.
This can happen if you are using queueEvent immediately after onResume in the Activity.
I did the experiment with glClearColor and even though it called the command without any exceptions, the background had not changed. Maybe the GLContext is still not properly available and the commands do nothing.
Hope this helps!
When controlling OpenGL from other threads, if it is GLSurfaceView, we use queueEvent(). Then, in cases where OpenGL is created on SurfaceView (use eglCreateWindowSurface, eglMakeCurrent, etc.), how should I implement for operating OpenGL from other threads?
You can implement your own queueEvent.
Make a queue. (ArrayList<Runnable> mQueue)
queueEvent() adds Runnable instances to this queue(mQueue).
Your SurfaceView's rendering thread pops event from the queue.
invokes event.run()
Use locks (synchronized or explicit locks) to avoid problems.
In GLSurfaceView, there are 3 and 4 steps in a loop of GLThread and mQueue is protected by synchronized blocks.
see also: GLSurfaceView
PS: sorry for my poor english.
I am interested in creating a 2D drawing application for Android using touch input. I will be using a SurfaceView to accomplish this as it is the most efficient next to OpenGL, but for this application, it should now be an issue.
After reading the documentation and overview (http://developer.android.com/guide/topics/graphics/2d-graphics.html) of SurfaceView and Canvas drawing, it seems they recommend creating an inner class which extends Thread to handle the work for drawing.
This makes sense of course as to not lock up UI and offload the work to a secondary thread. However, I am unsure why they do not use an external class which extends Thread, or even better, why not use a Runnable that is external?
Is there a benefit to leaving this as an inner class? And is there a benefit to extending Thread as opposed to implementing Runnable for Canvas drawing?
Thanks!
Well in their scenario they got one thing right and one thing wrong IMO:
The decision to make the thread class an inner class is ok, because that class is only required in that particular part of the code, so no need to expose it to the outside.
I don't really agree with extending Thread. The best practice is to implement Runnable and override the run method. This is because you can use that Runnable in several different ways, like starting a normal thread, queuing it up in a thread pool, etc. It also allows you to extend a different class if you need, since Runnable is just an interface.
I am creating a game loop and I need to be able to call onDrawFrame (from inside the renderer manually) in order to "skip frames" if I find that I am falling behind on processes.
Currently I have a GLSurfaceView class that calls
setRenderer(glSurfaceRenderer);
With this set up I understand that onDrawFrame is called every tick.
I tried putting the above call inside a method so that I could call it from inside my game loop but on the second run of the game loop I crash with the message saying
setRenderer has already been called for this instance
Is there a way to call the renderer manually every frame
Will just calling the
onDrawFrame
method work properly. Or is it not good practice to control the renderer in such a way when using openGL
I don't see how calling setRenderer() nor manually calling onDrawFrame() in the game loop will solve anything. You should refactor your rendering calls to take into account the time it takes draw so in other words time based animation. In any case manually calling onDrawFrame() without a call to eglMakeCurrent() before any drawing calls won't work as you have both the renderer and game loop thread drawing.
Edit: Since you are using GLSurfaceView, you can call requestRender() from your game loop to trigger a render if you feel RENDERMODE_CONTINUOUSLY is too slow for you.
What is better for a android game to use:
a SurfaceView with a rendering thread
or
a SurfaceView with a thread that calls the SurfaceView function doDraw()
Thanks.
The drawing in a SurfaceView is already handled in a separate thread. You do not need to spawn a new one.
See the API doc about it:
One of the purposes of this class is to provide a surface in which a secondary thread can render into the screen. If you are going to use it this way, you need to be aware of some threading semantics:
All SurfaceView and SurfaceHolder.Callback methods will be called from the thread running the SurfaceView's window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.
You must ensure that the drawing thread only touches the underlying Surface while it is valid -- between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed().