【问题标题】:Android native activity, GLES 3.0 shader compilations failsAndroid 原生活动,GLES 3.0 着色器编译失败
【发布时间】:2017-11-19 20:22:03
【问题描述】:

我想为个人项目尝试 Native Activity 和 GLES 3.0,直到遇到这个障碍:着色器不会加载和/或编译,我不太确定,因为 OPENGL 的日志不存在.

这是我的两个着色器:

static const char glVertexShader[] =
"#version 300 es\n"
"in vec4 vPosition;\n"
"void main()\n"
"{\n"
"  gl_Position = vPosition;\n"
"}\n\0";

static const char glFragmentShader[] =
"#version 300 es\n"
"precision mediump float;\n"
"void main()\n"
"{\n"
"  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n\0";

这是我的着色器加载和程序创建功能:

GLuint loadShader(GLenum shaderType, const char* shaderSource)
{
    GLuint shader = glCreateShader(shaderType);
    if (shader)
    {
        glShaderSource(shader, 1, &shaderSource, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled)
        {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen)
            {
                char * buf = new char[infoLen];
                if (buf)
                {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    log.log_error("Could not Compile Shader %d:\n%s\n", shaderType, buf);
                    delete[] buf;
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createProgram(const char* vertexSource, const char * fragmentSource)
{
    log.log_info("Loading vertex shader");
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
    if (!vertexShader)
    {
        log.log_info("Vertex shader load failure!");
        return 0;
    }
    log.log_info("Loading fragment shader");
    GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
    if (!fragmentShader)
    {
        log.log_info("Fragment shader load failure!");
        return 0;
    }
    GLuint program = glCreateProgram();

    if (program)
    {
        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

        if (linkStatus != GL_TRUE)
        {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength)
            {
                char* buf = new char[bufLength];
                if (buf)
                {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    log.log_error("Could not link program:\n%s\n", buf);
                    delete[] buf;
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

我还将在下面包含我的设置代码和绘图代码:

设置代码:

GLuint simpleTriangleProgram;
GLuint vPosition;
bool setupGraphics(int w, int h)
{
    simpleTriangleProgram = createProgram(glVertexShader, glFragmentShader);
    if (!simpleTriangleProgram)
    {
        log.log_error("Could not create program");
        return false;
    }
    vPosition = glGetAttribLocation(simpleTriangleProgram, "vPosition");
    glViewport(0, 0, w, h);
    return true;
}

绘图代码:

//-------------------------------
const GLfloat triangleVertices[] = {
    0.0f, 1.0f,
    -1.0f, -1.0f,
    1.0f, -1.0f
};
//-------------------------------


/**
* Just the current frame in the display.
*/
static void engine_draw_frame(struct engine* engine) {
    if (engine->display == NULL) {
        // No display.
        return;
    }

    // Just fill the screen with a color.
    glClearColor(((float)engine->state.x) / engine->width, engine->state.angle,
        ((float)engine->state.y) / engine->height, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    //---------------------------------------------------
    glUseProgram(simpleTriangleProgram);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
    glEnableVertexAttribArray(vPosition);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    //---------------------------------------------------

    eglSwapBuffers(engine->display, engine->surface);
}

是的,GLES 上下文已正确创建。 但如果我也应该发布该代码,请告诉我。

这是我的上下文创建代码:

/**
* Initialize an EGL context for the current display.
*/
static int engine_init_display(struct engine* engine) {
    // initialize OpenGL ES and EGL

    /*
    * 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_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_NONE
    };
    EGLint w, h, format;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, 0, 0);

    /* Here, the application chooses the configuration it desires.
    * find the best match if possible, otherwise use the very first one
    */
    eglChooseConfig(display, attribs, NULL, 0, &numConfigs);
    std::unique_ptr<EGLConfig[]> supportedConfigs(new EGLConfig[numConfigs]);
    assert(supportedConfigs);
    eglChooseConfig(display, attribs, supportedConfigs.get(), numConfigs, &numConfigs);
    assert(numConfigs);
    auto i = 0;
    for (; i < numConfigs; i++) {
        auto& cfg = supportedConfigs[i];
        EGLint r, g, b, d;
        if (eglGetConfigAttrib(display, cfg, EGL_RED_SIZE, &r) &&
            eglGetConfigAttrib(display, cfg, EGL_GREEN_SIZE, &g) &&
            eglGetConfigAttrib(display, cfg, EGL_BLUE_SIZE, &b) &&
            eglGetConfigAttrib(display, cfg, EGL_DEPTH_SIZE, &d) &&
            r == 8 && g == 8 && b == 8 && d == 0) {

            config = supportedConfigs[i];
            break;
        }
    }
    if (i == numConfigs) {
        config = supportedConfigs[0];
    }

    EGLint AttribList[] =
    {
        EGL_CONTEXT_CLIENT_VERSION, 3,
        EGL_NONE
    };

    /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
    * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
    * As soon as we picked a EGLConfig, we can safely reconfigure the
    * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
    surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
    context = eglCreateContext(display, config, NULL, AttribList);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
        log.log_warning("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    engine->display = display;
    engine->context = context;
    engine->surface = surface;
    engine->width = w;
    engine->height = h;
    engine->state.angle = 0;

    // Check openGL on the system
    auto opengl_info = { GL_VENDOR, GL_RENDERER, GL_VERSION, GL_EXTENSIONS };
    for (auto name : opengl_info) {
        auto info = glGetString(name);
        log.log_info("OpenGL Info: %s", info);
    }
    // Initialize GL state.
    // glEnable(GL_CULL_FACE);
    // glEnable(GL_DEPTH_TEST);

    return 0;
}

完整日志: Log pic

注意:我的记录器类只是__android_log_vprint() 的包装器。我没有包括它,因为它一点也不相关。

【问题讨论】:

  • 是的,没有空指针也没有任何东西。一切正常,除了着色器不编译/链接,不完全确定,因为 OpenGL 没有给我任何日志。
  • 哪位失败? '编译'是假的吗?
  • 来自我自己的代码......“顶点着色器加载失败”,然后它返回。但是片段着色器也是一样的。因此,我立即收到“无法创建程序”。
  • 因此,在“顶点着色器加载失败!”之前,您没有收到“无法编译着色器”日志记录!记录?发生这种情况的唯一方法是 glCreateShader 返回 0。几乎唯一发生的方法是 GLES 上下文未正确创建并设置为当前线程的上下文。
  • @Columbo 我已经用我的上下文创建代码和日志更新了我的问题(我目前不在我的开发 PC 上,所以我所能做的就是直接从我的手机中获取日志)。

标签: android c++ opengl-es android-ndk


【解决方案1】:

这个:

#version 300 es
attribute vec4 vPosition;
void main()
{
  gl_Position = vPosition;
}

... 不是合法的 ESSL 版本 300 着色器,因此您应该在您的平台上获得编译器返回的编译错误日志。你没有从你的 log_info 日志频道得到任何东西吗?

为了使着色器合法地将attribute替换为in

【讨论】:

  • 我用attribute 替换了in 更新了我的问题,但仍然没有呈现任何内容
【解决方案2】:

根据发布的日志,glCreateShader 返回 0,这仅在上下文无效时发生。

查看日志中的时间戳,您似乎在创建 OpenGLES 上下文之前加载了着色器。

【讨论】:

  • 哇。我没有意识到这一点。你不应该在void android_main(struct android_app* state) 上初始化你的上下文,而是在void engine_handle_cmd(struct android_app* app, int32_t cmd) 上,更具体地说,在cmd == APP_CMD_INIT_WINDOW 上。也就是说,上下文初始化必须在main() 中每次发生,而不仅仅是一次。这与我习惯的有点不同,但它解释了为什么它可以在 Windows 下运行,而不是在 Android 上运行。
猜你喜欢
  • 2017-10-05
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
  • 2021-12-31
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多