Native render thread and GLSurfaceView

1,501 views
Skip to first unread message

Belveder

unread,
Jan 24, 2010, 5:56:52 AM1/24/10
to android-ndk
Hi,

unfortunately I'm not an expert in rendering at all, and I don't
actually know how this can be done natively and works in combination
with the GLSurfaceView. Sorry if this is a noob question, but I think
a lot of people do what I intend to do. However, I have not found any
example of this on the web, so here's my actual question:

I have an application which has a full-screen activity/window, and I
have a renderer which is pure native C++ code and does some
computation and some drawing. However, the computation part can take
some variable amount of time. To make things more clear, here's some
code:

========================
<MyActivity.java>

package com.funny.mypkg;
import ...

public class MyActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
glSurface = new MyGLSurfaceView(this);
setContentView(glSurface);
renderwrapper = new NativeRendererWrapper();
}
...
@Override
public void onResume()
{
super.onResume();
renderthread = new Thread(renderwrapper);
renderthread.start();
}

@Override
public void onPause()
{
super.onPause();
renderwrapper.setStopFlag();
try {
renderthread.join(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
...
static {
System.loadLibrary("NativeRendererWrapped");
}

String tag = "MyActivity";
private MyGLSurfaceView glSurface;
NativeRendererWrapper renderwrapper;
Thread renderthread;
}

class MyGLSurfaceView extends GLSurfaceView
{
public MyGLSurfaceView(Context context)
{
super(context);
}

public void surfaceChanged(SurfaceHolder holder, int format, int
w, int h)
{
Log.i(tag, "surfaceChanged: " + format + " " + w + " " + h);
}
private String tag = "MyGLSurfaceView";
}
========================
<NativeRendererWrapper.java>

package com.funny.mypkg;
import ...

class NativeRendererWrapper implements Runnable
{
String tag = "NativeRendererWrapper";
public NativeRendererWrapper()
{
nativeInit();
}

public void run ()
{
nativeRun();
}

public void setStopFlag()
{
nativeStop();
}

// declare native renderer control methods here;
private static native void nativeInit();
private static native void nativeRun();
private static native void nativeStop();
}
========================
<NativeRenderer.h>
#include...

class NativeRenderer {
public:
NativeRenderer() : stopFlag(false) {};
~NativeRenderer() {};
void setStopFlag() {stopFlag=true;}
void run();
private:
bool stopFlag;
};

========================
<NativeRenderer.cpp>

static NativeRenderer *renderer = 0;

#include...
void NativeRenderer::run()
{
while(!stopFlag)
{
// compute something
// render something
}
}

void
Java_com_funny_mypkg_NativeRendererWrapper_nativeInit( JNIEnv* env )
{
renderer = new NativeRenderer();
}

void
Java_com_funny_mypkg_NativeRendererWrapper_nativeRun( JNIEnv* env )
{
renderer->run();
}


void
Java_com_funny_mypkg_NativeRendererWrapper_nativeStop( JNIEnv* env )
{
renderer->setStopFlag();
}
========================

So far, so good. I import the GLES stuff like it is done in the
sanangeles example, and everything works, including the glEnable(...)
and so on stuff. The thread starts, runs and stops as expected, but no
drawing happens. Now, how can I get the drawing to be done actually?
What is missing here? In my understanding I have to pass the
"context" to the native renderer and refer to it there I guess, but
how can I achieve this? I read the documentation of the
GLSurfaceView.Renderer, but I see no way to use with it and I doubt
this is useful to me in my case. Do I have to stick to something
completely different instead of GLSurfaceView?

Any help is highly appreciated.
Regards

Roderick Colenbrander

unread,
Jan 24, 2010, 9:20:12 AM1/24/10
to android-ndk
You also need to implement onDrawFrame. From there you should call
your native code. Under the hood the renderer runs in a 'infinite
loop' and calls onDrawFrame. After onDrawFrame it performs a buffer
swap. Then the next iteration you should draw the second frame adn so
on.

Roderick

Belveder

unread,
Jan 24, 2010, 1:08:51 PM1/24/10
to android-ndk
Hi,

thanks for the reply. I know that the sanangeles demo works like that,
adding a renderer to the glsurfaceview and calling the render stuff
explicitly in onDrawFrame. But this what I do not want to do if I can
avoid it. Calling it from onDrawFrame would mean that the onDrawFrame
function controls each iteration of my applications main loop. An
alternative solution I see is to store the results that should be
rendered in my application main loop after each iteration, and pick
them up by the rendering code called from onDrawFrame.

Regards...


On 24 Jan., 15:20, Roderick Colenbrander <thunderbir...@gmail.com>
wrote:

Belveder

unread,
Jan 24, 2010, 1:12:23 PM1/24/10
to android-ndk
Probably I should mention that the rendering stuff does not have
priority in the application I target. It's more important that the
main loop runs as many iterations per second as possible - the main
loop should not be slowed down by rendering if possible...

Roderick Colenbrander

unread,
Jan 24, 2010, 1:58:13 PM1/24/10
to android-ndk
When you use GLSurfaceview and friends the main loop is in the java
code (see
http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=opengl/java/android/opengl/GLSurfaceView.java;h=9ca57bae7a1fe1d6ec818169d2fcc205276ea0e0;hb=HEAD#l1000).

The java code isn't very inefficient at all. In quake3 I get a very
good framerate and only a small part of time is spent in the Java
code. At 854x480 @ 30fps in the game about 10% of the time is spent
outside my onDrawFrame. There is 3ms between each new onDrawFrame
call. You might say that this is a lot but it isn't really since the
java loop also performs the eglSwapBuffers which is a very heavy call.

If you want to be in control yourself you have to use EGL directly and
do everything yourself. E.g. context creation, pixelformat selection
and so on.

Roderick

Belveder

unread,
Jan 25, 2010, 1:34:15 PM1/25/10
to android-ndk
Roderick,

thanks for your help. As you suggested I'm now using the renderer
issuing each iteration of the main loop from onDrawFrame and it works
surprisingly well. I think I'll stick with it...

Regards

On Jan 24, 7:58 pm, Roderick Colenbrander <thunderbir...@gmail.com>
wrote:


> When you use GLSurfaceview and friends the main loop is in the java

> code (seehttp://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;...).

Reply all
Reply to author
Forward
0 new messages