Resizing NativeActivity and OpenGL surfaces

2,630 views
Skip to first unread message

David Given

unread,
Mar 19, 2012, 10:50:59 AM3/19/12
to andro...@googlegroups.com
I have an Android NDK-based application (which I didn't write) that uses
OpenGL and EGL.

I'm finding that Android's behaviour with regards to setting the screen
size is really, really bizarre. Apparently Java, ANativeWindow and EGL
have different ideas as to how big the screen is. Ideally the three
sizes should always be the same, but this turns out not to be the case.

On application startup, after I get AGP_CMD_INIT_WINDOW, Java gets the
size right, but EGL and ANativeWindow think the screen is 1x1. The EGL
and ANativeWindow size only get updated after I create an EGL surface,
context, bind them, and then draw on the screen with eglSwapBuffers().

when the application's screen changes size, I get sent a
AGP_CMD_CONFIG_CHANGED. Java's size has changed. But ANativeWindow's
size only changes a couple of events later, and EGL's size, again, only
changes after I've drawn on the screen.

if I put the application to the background (I get an
AGP_CMD_TERM_WINDOW), change the orientation, and bring it to the
foreground (AGP_CMD_INIT_WINDOW), Java's size has updated. But
ANativeWindow and EGL's size don't update until later... if they update
at all, which sometimes they don't!

I find the behaviour changes drastically depending on what device I'm
on. The worst culprit is a Samsung Galaxy Y running 2.3.6. I'm quite
willing to believe that given Samsung's history, at least some of this
is due to the vendor subtly breaking stuff --- but it doesn't really
matter; I have to make this work anyway.

My attempts to work around the above issues are resulting in an
ever-more complex and brittle state machine and it's becoming completely
unworkable. Normally I'd just copy someone else code, but unfortunately
the NDK doesn't come with any NativeActivity OpenGL samples!

Can anyone point me at a known correct implementation of handing screen
resizing, backgrounding etc using NativeActivity and OpenGL that I can
use for reference?

--
┌─── dg@cowlark.com ───── http://www.cowlark.com ─────
│ "Parents let children ride bicycles on the street. But parents do not
│ allow children to hear vulgar words. Therefore we can deduce that
│ cursing is more dangerous than being hit by a car." --- Scott Adams

signature.asc

David Given

unread,
Mar 20, 2012, 6:37:36 AM3/20/12
to andro...@googlegroups.com
David Given wrote:
[...]

> I'm finding that Android's behaviour with regards to setting the screen
> size is really, really bizarre.

Does anyone know *anything* about this? This issue is blocking our
entire product, and I need assistance...

signature.asc

gadget

unread,
Mar 20, 2012, 1:24:13 PM3/20/12
to android-ndk
I don't have a direct answer to your question, but I've gone through
NativeActivity code enough times, that I feel like I could give you
some ideas to explore. You might already know all this, but since no
one else has answered, I will chime in.

First things first. Take a look (if you already haven't) at the Java
and Native sides of NativeActivity:
c side: https://github.com/android/platform_frameworks_base/blob/master/core/jni/android_app_NativeActivity.cpp
java side: http://www.java2s.com/Open-Source/Android/android-core/platform-frameworks-base/android/app/NativeActivity.java.htm

The c-side gets events by reading them off of a file descriptor, as
supplied by the main-thread java wrapper. This would explain a slight
delay that you're describing between when Java gets the event and when
the native side finally receives it.

If you're using your ANativeWindow for creating an egl surface, you
won't get the size until you eglCreateContext and eglMakeCurrent.
After this calls to eglQuerySurface will give you what you want.

As for dealing with changes in orientation -- I believe the java
surface will get destroyed, and recreated in the new orientation. As
such, you will need to release your old native window and make a new
one from what is passed in to the onSurfaceChanged. The eglContext and
texture data will need to be recreated/reloaded. Same also applies to
losing your window and getting it back in the same orientation (ie.
you go through TERM_WINDOW).

Native Activity is somewhat of a monkey-paw trap, looks very appealing
at first, but reveals its weaknesses only when you start writing. My
advice is to avoid it completely and write your own Java wrapper
(double or single threaded). You will get a much finer control over
what you want to do that way (though I understand that in your case it
might already be too late).

Hope this gives you some ideas, at least.
>  signature.asc
> < 1KViewDownload

chinlin@tw-roc

unread,
Apr 21, 2012, 11:22:22 AM4/21/12
to andro...@googlegroups.com
It looks like the problem that native activity is destroyed again and again when you rotate your device.
I think you can add configChanges with orientation and screenSize in AndroidManifest.xml
not to let your NativeActivity to destroy your  activity again, and you won't get the INIT_WINDOW event again when rotating devices.

Regards, 
Chinlin

David Given於 2012年3月19日星期一UTC+8下午10時50分59秒寫道:

Max Cusick

unread,
Jan 28, 2014, 8:51:57 PM1/28/14
to andro...@googlegroups.com
Its so late, but maybe useful... I had the same problem - with eglQuerySurface in my NDK application i had surface size 1x1 on Android 2.3.6, Android 2.3.7 devices(some of them) and Genymotion emulator. 
It help for me to simply double call eglCreateWindowSurface(display, config, app->window, NULL) when I do eglInit. Or, if it doesnt work( thats I first of all to try), double eglInit on APP_CMD_INIT_WINDOW. smth like eglInit(); elgDestroy(); eglInit();

Best regards,
Max.


Rob Gold

unread,
Jul 17, 2014, 2:00:41 AM7/17/14
to andro...@googlegroups.com
I was running into this as well. Double calling eglCreateWindowSurface working when I was testing in Genymotion, but not when running on a Samsung Galaxy Ace which is version 2.3.6. It also seemed a little too hack & pray for me, anyway.

I've solved this in my app's activity class where I'm extending from NativeActivity, I override the surfaceChanged() function and then call a JNI wrapper function where I call and set the surface width and height in C code. Then when I'm initializing EGL I use the values that I got from the activity if eglQuerySurface returns a bogus value.

I'm not competently finished with my Android app, and I still need to create a splash screen starting activity. This solution might change a bit later, but for now it's working for me.
Reply all
Reply to author
Forward
0 new messages