c++ - Android NDK OpenGL ES 2 上下文初始化

标签 c++ opengl-es android-ndk

尝试使用 android-ndk-r8e 构建原生 android 应用程序。

如果构建为 Java + NDK 应用程序,即使用加载 .so 文件的 Java 接口(interface),初始化 OpenGL 并调用 .so 中的方法,代码编译良好并且运行没有问题。

但是,当编译为“ native 事件”时,在 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 正确打印消息“设置前”。如果您查看代码,它应该打印“设置后”。相反,它有时会打印“检测到堆栈损坏:中止”。其他时候它只是简单地退出循环,即使没有代码(我写的)让它那样返回。

我应该提一下,NDK 代码是基于这个 sample . Java 版本看起来几乎相同并且运行良好。

最佳答案

我很确定这是因为这条线

surface = eglCreateWindowSurface(display, configs[i], Canvas::Engine.app->window, NULL);

你或多或少假设的问题是,在从 0 到 numConfigs 的 for 循环中,你寻找一个在你的模拟器或设备中可能不可用的配置,所以如果你的代码永远不会达到那个中断,那么你创建你的表面和基于数组外部数据的上下文(因为在这种情况下我将是 numConfigs),这反过来会解释不稳定的行为。

关于c++ - Android NDK OpenGL ES 2 上下文初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16845921/

相关文章:

c++ - Qt Quick 2/QML 中等效的 StackPanel - 宽度问题

C++ 重载函数和子类

iphone - 在 iPhone 上绘制到 OpenGL ES 帧缓冲区并从中获取 UIImage

使用 x264 为 Android 构建 FFMPEG

c - 从客户端接收后,二进制文件的某些内容丢失

c++ - 如何使 lambda 与 std::nullopt 一起工作

c++ - 为什么括号中的AND与没有时的评价不同?

iphone - 哪些 AR 库对于开发用于显示某些对象信息的 iOS 应用程序很有用?

Android 在 onDrawFrame 中调用 GLUtils.texImage2D 非常慢

android-ndk - 为 _ZTVN10__cxxabiv### 符号获取三个 "346 cannot locate"