我正在编写本机 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有问题吗?检查我的着色器是否良好的参考设备是什么?