私はネイティブの 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
アップデート
この奇妙な動作を生成する特定のシェーダー ペアが 1 つあります。
正しくコンパイルされる他の 2 つのシェーダー ペアが見つかりましたが、リンクすると、「リンクに失敗しました」というログが生成されます。- それ以外の情報はありません。
次に、GPU エミュレーションを使用して Jelly Bean AVD でこれらの 2 つのシェーダー ペア (まったく同じ APK) を試してみました。それらは完全にリンクし、私のゲームはそこで動作します。
ここには非常に非常に一貫性のないものがあります...問題は私のHTC Desireにありますか? シェーダーが適切かどうかを確認するための適切な参照デバイスは何ですか?