1

我正在编写本机 Android OpenGLES 2 代码。

加载着色器时(着色器加载代码与 NDK 示例“hello-gl2”非常相似),我的程序没有链接(着色器本身编译没有错误)。

这段代码:

GLint linkStatus = GL_FALSE;
GLCALL(glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus));
if (linkStatus != GL_TRUE) {

返回false,所以我继续调用

LOGE("Could not link program, gathering log...");
GLint bufLength = 0;
GLCALL(glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &bufLength));

它永远不会返回并使我的应用程序崩溃。LogCat 显示为红色:

04-19 15:24:55.369: A/<unknown>(29293): stack corruption detected: aborted
04-19 15:24:55.379: I/ActivityManager(101): Process x.x.x (pid 29293) has died.

我可以假设日志检索函数内部出现问题,因为我向它传递了一个普通的 GLint 引用,这与 Google 示例中的代码相同......

我试过跳过长度查询,直接查询日志,但它会产生同样的错误。

我可以在这里发布整个 GLSL 着色器代码,但让日志功能正常工作会更有价值,这样我就可以自己调试它......

完整的着色器加载代码:

GLuint OpenGLESHelper::loadShader(GLenum shaderType, const char* pSource) {
    GLuint shader;
    GLCALL(shader = glCreateShader(shaderType));
    if (shader) {
        GLCALL(glShaderSource(shader, 1, &pSource, NULL));
        GLCALL(glCompileShader(shader));
        GLint compiled = 0;
        GLCALL(glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
        if (!compiled) {
            LOGE("Could not compile shader, retrieving log...");
            GLint infoLen = 0;
            GLCALL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));

            // Workaround
            if (infoLen == 0)
                infoLen = 4096;

            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf) {
                    GLCALL(glGetShaderInfoLog(shader, infoLen, NULL, buf));
                    LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
                    free(buf);
                }
                GLCALL(glDeleteShader(shader));
                shader = 0;
            }
        }
    }
    return shader;
}

ShaderProgram* OpenGLESHelper::createProgram(const char* pVertexSource,
        const char* pFragmentSource) {
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!pixelShader) {
        return 0;
    }

    GLuint programId;
    GLCALL(programId = glCreateProgram());
    if (programId) {
        GLCALL(glAttachShader(programId, vertexShader));
        GLCALL(glAttachShader(programId, pixelShader));
        GLCALL(glLinkProgram(programId));
        GLint linkStatus = GL_FALSE;
        GLCALL(glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus));
        if (linkStatus != GL_TRUE) {
            LOGE("Could not link program, gathering log...");
            GLint bufLength = 0;
            GLCALL(glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &bufLength));

            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    GLCALL(glGetProgramInfoLog(programId, bufLength, NULL, buf));
                    LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            GLCALL(glDeleteProgram(programId));
            programId = 0;
        }
    }

    ShaderProgram* program = new ShaderProgram;
    program->mProgramHandle = programId;

    GLCALL(
            program->mPositionAttributeHandle = glGetAttribLocation(programId, "vPosition"));
    GLCALL(
            program->mTexCoordAttributeHandle = glGetAttribLocation(programId, "a_TexCoordinate"));
    GLCALL(
            program->mTextureUniformHandle = glGetUniformLocation(programId, "rubyTexture"));
    GLCALL(
            program->mTextureSizeUniformHandle = glGetUniformLocation(programId, "rubyTextureSize"));

    return program;
}

使用的预处理器宏:

  #ifdef ANDROID_DEBUG_GL_CALLS
#define GLCALLLOG(x, before) \
    do { \
        if (before) \
            LOGD("calling '%s' (%s:%d)", x, __FILE__, __LINE__); \
        else \
            LOGD("returned from '%s' (%s:%d)", x, __FILE__, __LINE__); \
    } while (false)
#else
#define GLCALLLOG(x, before) do {  } while (false)
#endif

#define GLCALL(x) \
    do { \
        GLCALLLOG(#x, true); \
        (x); \
        GLCALLLOG(#x, false); \
        checkGlError(#x, __FILE__, __LINE__); \
    } while (false)

#define GLTHREADCHECK \
    do { \
        assert(pthread_self() == _main_thread); \
    } while (false)

#else
#define GLCALL(x) do { (x); } while (false)
#define GLTHREADCHECK do {  } while (false)
#endif

更新

有一个特殊的着色器对产生了这种奇怪的行为。

我发现了另外 2 个正确编译的着色器对,但是当链接时,生成一个只有“链接失败”的日志。- 除此之外没有任何信息。

然后我在带有 GPU 仿真的 Jelly Bean AVD 上尝试了这两个着色器对(完全相同的 APK),它们完美地链接在一起,我的游戏在那里运行。

这里非常非常非常不一致的东西......我的HTC Desire有问题吗?检查我的着色器是否良好的参考设备是什么?

4

0 回答 0