I am writing native Android OpenGLES 2 code.
When loading shaders (shader loading code is very similar to the NDK sample "hello-gl2"), my program does not link (shaders themselves compile without errors).
This code:
GLint linkStatus = GL_FALSE;
GLCALL(glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus));
if (linkStatus != GL_TRUE) {
Returns false, so I proceed to calling
LOGE("Could not link program, gathering log...");
GLint bufLength = 0;
GLCALL(glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &bufLength));
Which never returns and crashes my app. LogCat shows in red:
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.
I can assume that something goes wrong inside the log retrieving function, because I pass it a normal GLint reference, and this is the same code from the Google example...
I've tried skipping the length querying and just query the log directly, but it generates the same error.
I could post here the whole GLSL shader code but it would be more valuable to just have the log function working so I can debug it myself...
The full shader loading code:
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;
}
The used preprocessor macros:
#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
UPDATE
There was one particular shader pair which generated this weird behavior.
I found 2 other shader pairs that compile correctly, but when linked, generate a log with just "Link failed." - no info beside that.
Then I tried those 2 shader pairs (exact same APK) on a Jelly Bean AVD with GPU emulation, and they link together perfectly and my game works there.
Very, very, very inconsistent stuff here... Is the problem with my HTC Desire? What would be a good reference device for checking if my shaders are good or not?