Android NDK OpenGL ES 2上下文初始化
Android NDK OpenGL ES 2 Context Initialization
尝试使用android-ndk-r8e构建一个本地android应用程序。
代码编译良好,运行没有问题,如果构建为Java + NDK应用程序,这是一个Java接口加载.so
文件,初始化OpenGL和调用。so中的方法。
然而,当作为"本机活动"编译时,在setup()函数(如下代码)之后,LogCat输出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;
}
下面是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();
}
// ..
}
这里是我处理Android窗口命令的地方。
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正确打印消息"before setup"。如果你看一下代码,它应该打印"after setup"。相反,它有时会打印"堆栈损坏检测到:中止"。其他时候,它只是简单地退出循环,即使没有代码(我写的)使它像那样返回。
我应该提到NDK代码是基于这个示例的。Java版本看起来差不多,运行也很好。我很确定是因为这一行
surface = eglCreateWindowSurface(display, configs[i], Canvas::Engine.app->window, NULL);
您或多或少假设的问题是,在从0到numConfigs的for循环中,您寻找的配置可能在您的模拟器或设备中不可用,因此,如果您的代码从未达到该断点,那么您将基于数组之外的数据创建表面和上下文(因为在这种情况下我将是numConfigs),这反过来将解释不稳定的行为。
相关文章:
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- GTKmm Opengl 上下文未初始化
- 在上下文初始化之前查询支持的最高 OpenGL 版本?
- 如何使用GSOAP初始化服务器上下文以启用简单身份验证(仅服务器身份验证)
- log4cplus:ERROR在默认上下文已被销毁后重新初始化
- 如何使用win32从多线程上下文初始化线程基元
- 在渲染以外的另一个线程中初始化 OpenGL 上下文
- OPENCV :不同方法的 CUDA 上下文初始化
- Android NDK OpenGL ES 2上下文初始化
- OpenCL - c++包装器-动态库中的上下文取消初始化导致访问冲突
- SSL握手错误:会话id上下文未初始化