Trying to build a native android application using android-ndk-r8e.
Code compiles fine and runs without issues if building as Java + NDK app, that is with a Java interface that loads an .so
file, initializes OpenGL and calls the methods in the .so.
However, when compiled as a "native-activity", after setup() function (code below), LogCat outputs A//system/bin/app_process(27426): stack corruption detected: aborted
void Canvas::Setup ( void )
{
// initialize OpenGL ES 2
// Here specify the attributes of the desired configuration.
// Below, we select an EGLConfig with at least 8 bits per color
// component compatible with on-screen windows
const EGLint attribs[] =
{
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_NONE
};
// ..
// surface, window and context related data
EGLint w,
h,
dummy,
format;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay( EGL_DEFAULT_DISPLAY );
// ..
eglInitialize(display, 0, 0);
// get the number of matching EGL configurations
int num_config[1];
eglChooseConfig(display, attribs, NULL, 1, num_config);
const int numConfigs = num_config[0];
if (numConfigs <= 0)
{
//throw new IllegalArgumentException("No configs match configSpec");
}
// allocate then read the array of minimally matching EGL configs
EGLConfig configs[numConfigs];
EGLConfig current;
eglChooseConfig(display, attribs, configs, numConfigs, num_config);
int i = 0;
for(; i < numConfigs; ++i)
{
int d = 2, s = 2, r, g, b, a;
eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &d);
eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &s);
// we need at least mDepthSize and mStencilSize bits
if (d < 1 || s < 0)
{
continue;
}
// we want an *exact* match for red/green/blue/alpha
eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &r);
eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &a);
if (r == 8 && g == 8 && b == 8 && a == 8)
{
// found it, store in i
break;
}
}
surface = eglCreateWindowSurface(display, configs[i], Canvas::Engine.app->window, NULL);
int attrib_list[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
context = eglCreateContext(display, configs[i], EGL_NO_CONTEXT, attrib_list);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
{
LOG_PRINT_ERROR("Unable to eglMakeCurrent");
}
Canvas::Engine.display = display;
Canvas::Engine.context = context;
Canvas::Engine.surface = surface;
Canvas::Engine.animating = true;
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
Canvas::Width = w;
Canvas::Width = h;
}
Below is android_main
void android_main(struct android_app* state)
{
// make sure glue isn't stripped.
app_dummy();
// ..
// hook to events
memset(&Canvas::Engine, 0, sizeof(Canvas::Engine));
state->userData = &Canvas::Engine;
state->onAppCmd = Canvas::HandleCommand;
state->onInputEvent = Canvas::HandleInput;
Canvas::Engine.app = state;
// ..
// loop waiting for stuff to do
while (1)
{
// read all pending events.
int ident;
int events;
struct android_poll_source* source;
// If not animating, we will block forever waiting for events.
// If animating, we loop until all events are read, then continue
// to draw the next frame of animation.
while ((ident=ALooper_pollAll(Canvas::Engine.animating ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
{
// process this event.
if (source != NULL)
{
source->process(state, source);
}
// check if we are exiting.
if (state->destroyRequested != 0)
{
Canvas::Cleanup();
return;
}
}
Canvas::Render();
}
// ..
}
Here is where I handle Android window commands.
void Canvas::HandleCommand(struct android_app* app, int32_t cmd)
{
switch (cmd)
{
case APP_CMD_INIT_WINDOW:
// window is being shown, get it ready
LOG_PRINT_INFO("before setup");
Canvas::Setup();
LOG_PRINT_INFO("after setup");
LOG_PRINT_INFO("before resize);
Canvas::Resize(Canvas::Engine.width, Canvas::Engine.height);
LOG_PRINT_INFO("after resize);
break;
case APP_CMD_TERM_WINDOW:
// window is being hidden or closed, clean it up
Canvas::Cleanup();
break;
}
}
LogCat prints correctly the message "before setup". If you look at the code, it should print "after setup". Instead it prints "stack corruption detected: aborted" sometimes. Other times it just plain exits the loop, even though there's no code (that I've written) to make it return like that.
I should mention that the NDK code is based on this sample. The Java version pretty much looks the same and runs fine.
I'm pretty sure it's because of this line
surface = eglCreateWindowSurface(display, configs[i], Canvas::Engine.app->window, NULL);
Your more or less hypothetical problem there is that in your for loop from 0 to numConfigs you look for a configuration that might not be available in your emulator or device, so if your code never reaches that break, then you create your surface and context based on data outside of your array (because i will be numConfigs in this case), which in turn would explain the erratic behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With