私は、OpenGLとGLSLを使用して、GPU Gems3の最初の章で詳しく説明したものと同様のマーチングキューブアルゴリズムの2パスGPU実装を作成しようとしています。ただし、glDrawArrays
最初のパスでのへの呼び出しは、一貫して。で失敗しますGL_INVALID_OPERATION
。
私は見つけることができるすべてのドキュメントを調べて、glDrawArrays
そのエラーをスローする可能性があるこれらの条件を見つけました:
GL_INVALID_OPERATION
ゼロ以外のバッファオブジェクト名が有効な配列またはGL_DRAW_INDIRECT_BUFFER
バインディングにバインドされており、バッファオブジェクトのデータストアが現在マップされている場合に生成されます。GL_INVALID_OPERATION
の実行と対応するglDrawArrays
の実行の間に実行された場合に生成されます。glBegin
glEnd
GL_INVALID_OPERATION
現在のプログラムオブジェクト内の2つのアクティブなサンプラーが異なるタイプであるglDrawArrays
かどうかによって生成されますが、同じテクスチャ画像ユニットを参照します。glDrawElements
GL_INVALID_OPERATION
ジオメトリシェーダーがアクティブで、モードが現在インストールされているプログラムオブジェクトのジオメトリシェーダーの入力プリミティブタイプと互換性がない場合に生成されます。GL_INVALID_OPERATION
モードがGL_PATCHES
あり、テッセレーション制御シェーダーがアクティブでない場合に生成されます。GL_INVALID_OPERATION
プリミティブの頂点を変換フィードバックの目的で使用されているバッファオブジェクトに記録すると、バッファオブジェクトのサイズの制限を超えるか、で設定されている終了位置オフセット+サイズ-1を超える場合に生成されglBindBufferRange
ます。GL_INVALID_OPERATION
glDrawArrays()
ジオメトリシェーダーが存在せず、変換フィードバックがアクティブであり、モードが許可されたモードの1つではない場合に生成されます。GL_INVALID_OPERATION
glDrawArrays()
は、ジオメトリシェーダーが存在し、変換フィードバックがアクティブであり、ジオメトリシェーダーの出力プリミティブタイプが変換フィードバックprimitiveModeと一致しない場合に生成されます。GL_INVALID_OPERATION
バインドされたシェーダープログラムが無効な場合に生成されます。- 編集10/10/12:
GL_INVALID_OPERATION
変換フィードバックが使用されている場合に生成され、変換フィードバックバインディングポイントにバインドされたバッファーも配列バッファーバインディングポイントにバインドされます。これは、私がバインドしたバッファーのタイプミスが原因で発生していた問題です。仕様にはこれは違法であると記載されていますが、私が見つけたドキュメントでは、エラーをスローする理由の1つとしてglDrawArraysの下にリストされていません。
残念ながら、私が見つけることができる公式のドキュメントの1つは、これらのうち3つ以上をカバーしていません。私はこのリストを多くの情報源から収集しなければなりませんでした。ポイント7と8は、実際にはのドキュメントに基づいてglBeginTransformFeedback
おり、ポイント9はまったくドキュメント化されていないようです。どこかのフォーラム投稿で言及されているのを見つけました。しかし、私が得ているエラーを説明しているようには見えないので、このリストはまだ完全ではないと思います。
- 私は自分のプログラムのどこにも、バッファをまったくマッピングしていません。
- 私はコアプロファイルを使用しているので
glBegin
、glEnd
利用できません。 - 私は2つのサンプラーを持っていて、それらは異なるタイプですが、それらは間違いなく異なるテクスチャーにマッピングされています。
- ジオメトリシェーダーはアクティブですが、その入力レイアウトは
layout (points) in
であり、glDrawArrays
で呼び出されていGL_POINTS
ます。 - 私は
GL_PATCHES
いかなる種類のテッセレーションシェーダーも使用していません。 - ジオメトリシェーダーが出力できる最大のスペースを割り当てていることを確認しました。それから私はそれを4倍にしてみました。助けにはならなかった。
- ジオメトリシェーダーがあります。次のポイントを参照してください。
- 変換フィードバックが使用されており、ジオメトリシェーダーがありますが、出力レイアウトは
layout (points) out
でglBeginTransformFeedback
呼び出されGL_POINTS
ます。 glValidateProgram
の呼び出しの直前にへの呼び出しを挿入しようとしましたglDrawArrays
が、が返されGL_TRUE
ました。
実際のOpenGLコードは次のとおりです。
const int SECTOR_SIZE = 32;
const int SECTOR_SIZE_CUBED = SECTOR_SIZE * SECTOR_SIZE * SECTOR_SIZE;
const int CACHE_SIZE = SECTOR_SIZE + 3;
const int CACHE_SIZE_CUBED = CACHE_SIZE * CACHE_SIZE * CACHE_SIZE;
MarchingCubesDoublePass::MarchingCubesDoublePass(ServiceProvider* svc, DensityMap* sourceData) {
this->sourceData = sourceData;
densityCache = new float[CACHE_SIZE_CUBED];
}
MarchingCubesDoublePass::~MarchingCubesDoublePass() {
delete densityCache;
}
void MarchingCubesDoublePass::InitShaders() {
ShaderInfo vertShader, geoShader, fragShader;
vertShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass1.vert", GL_VERTEX_SHADER);
svc->shader->Compile(vertShader);
geoShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass1.geo", GL_GEOMETRY_SHADER);
svc->shader->Compile(geoShader);
shaderPass1 = glCreateProgram();
static const char* outputVaryings[] = { "triangle" };
glTransformFeedbackVaryings(shaderPass1, 1, outputVaryings, GL_SEPARATE_ATTRIBS);
assert(svc->shader->Link(shaderPass1, vertShader, geoShader));
uniPass1DensityMap = glGetUniformLocation(shaderPass1, "densityMap");
uniPass1TriTable = glGetUniformLocation(shaderPass1, "triangleTable");
uniPass1Size = glGetUniformLocation(shaderPass1, "size");
attribPass1VertPosition = glGetAttribLocation(shaderPass1, "vertPosition");
vertShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.vert", GL_VERTEX_SHADER);
svc->shader->Compile(vertShader);
geoShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.geo", GL_GEOMETRY_SHADER);
svc->shader->Compile(geoShader);
fragShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.frag", GL_FRAGMENT_SHADER);
svc->shader->Compile(fragShader);
shaderPass2 = glCreateProgram();
assert(svc->shader->Link(shaderPass2, vertShader, geoShader, fragShader));
uniPass2DensityMap = glGetUniformLocation(shaderPass2, "densityMap");
uniPass2Size = glGetUniformLocation(shaderPass2, "size");
uniPass2Offset = glGetUniformLocation(shaderPass2, "offset");
uniPass2Matrix = glGetUniformLocation(shaderPass2, "matrix");
attribPass2Triangle = glGetAttribLocation(shaderPass2, "triangle");
}
void MarchingCubesDoublePass::InitTextures() {
for (int x = 0; x < CACHE_SIZE; x++) {
for (int y = 0; y < CACHE_SIZE; y++) {
for (int z = 0; z < CACHE_SIZE; z++) {
densityCache[x + y*CACHE_SIZE + z*CACHE_SIZE*CACHE_SIZE] = sourceData->GetDensity(Vector3(x-1, y-1, z-1));
}
}
}
glGenTextures(1, &densityTex);
glBindTexture(GL_TEXTURE_3D, densityTex);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, CACHE_SIZE, CACHE_SIZE, CACHE_SIZE, 0, GL_RED, GL_FLOAT, densityCache);
glGenTextures(1, &triTableTex);
glBindTexture(GL_TEXTURE_RECTANGLE, triTableTex);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_R16I, 16, 256, 0, GL_RED_INTEGER, GL_INT, triTable);
}
void MarchingCubesDoublePass::InitBuffers() {
float* voxelGrid = new float[SECTOR_SIZE_CUBED*3];
unsigned int index = 0;
for (int x = 0; x < SECTOR_SIZE; x++) {
for (int y = 0; y < SECTOR_SIZE; y++) {
for (int z = 0; z < SECTOR_SIZE; z++) {
voxelGrid[index*3 + 0] = x;
voxelGrid[index*3 + 1] = y;
voxelGrid[index*3 + 2] = z;
index++;
}
}
}
glGenBuffers(1, &bufferPass1);
glBindBuffer(GL_ARRAY_BUFFER, bufferPass1);
glBufferData(GL_ARRAY_BUFFER, SECTOR_SIZE_CUBED*3*sizeof(float), voxelGrid, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &bufferPass2);
glBindBuffer(GL_ARRAY_BUFFER, bufferPass2);
glBufferData(GL_ARRAY_BUFFER, SECTOR_SIZE_CUBED*5*sizeof(int), NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &vaoPass1);
glBindVertexArray(vaoPass1);
glBindBuffer(GL_ARRAY_BUFFER, bufferPass1);
glVertexAttribPointer(attribPass1VertPosition, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(attribPass1VertPosition);
glBindVertexArray(0);
glGenVertexArrays(1, &vaoPass2);
glBindVertexArray(vaoPass2);
glBindBuffer(GL_ARRAY_BUFFER, bufferPass2);
glVertexAttribIPointer(attribPass2Triangle, 1, GL_INT, 0, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(attribPass2Triangle);
glBindVertexArray(0);
glGenQueries(1, &queryNumTriangles);
}
void MarchingCubesDoublePass::Register(Genesis::ServiceProvider* svc, Genesis::Entity* ent) {
this->svc = svc;
this->ent = ent;
svc->scene->RegisterEntity(ent);
InitShaders();
InitTextures();
InitBuffers();
}
void MarchingCubesDoublePass::Unregister() {
if (!ent->GetBehavior<Genesis::Render>()) {
svc->scene->UnregisterEntity(ent);
}
}
void MarchingCubesDoublePass::RenderPass1() {
glEnable(GL_RASTERIZER_DISCARD);
glUseProgram(shaderPass1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, densityTex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_RECTANGLE, triTableTex);
glUniform1i(uniPass1DensityMap, 0);
glUniform1i(uniPass1TriTable, 1);
glUniform1i(uniPass1Size, SECTOR_SIZE);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferPass2);
glBindVertexArray(vaoPass2);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryNumTriangles);
glBeginTransformFeedback(GL_POINTS);
GLenum error = glGetError();
glDrawArrays(GL_POINTS, 0, SECTOR_SIZE_CUBED);
error = glGetError();
glEndTransformFeedback();
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glBindVertexArray(0);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
glUseProgram(0);
glDisable(GL_RASTERIZER_DISCARD);
glGetQueryObjectuiv(queryNumTriangles, GL_QUERY_RESULT, &numTriangles);
}
void MarchingCubesDoublePass::RenderPass2(Matrix mat) {
glUseProgram(shaderPass2);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, densityTex);
glUniform1i(uniPass2DensityMap, 0);
glUniform1i(uniPass2Size, SECTOR_SIZE);
glUniform3f(uniPass2Offset, 0, 0, 0);
mat.UniformMatrix(uniPass2Matrix);
glBindVertexArray(vaoPass2);
glDrawArrays(GL_POINTS, 0, numTriangles);
glBindVertexArray(0);
glUseProgram(0);
}
void MarchingCubesDoublePass::OnRender(Matrix mat) {
RenderPass1();
RenderPass2(mat);
}
実際のエラーは、の呼び出しglDrawArrays
ですRenderPass1
。とへの呼び出しをコメントアウトするglBeginTransformFeedback
とglEndTransformFeedback
、glDrawArrays
エラーの生成が停止することに注意してください。ですから、何が悪いのかは、おそらく何らかの形で変換フィードバックに関連しています。
8/18 / 12、午後9時を編集:
gDEBuggerでNVIDIAGLExpert機能を見つけましたが、これは以前はなじみがありませんでした。これをオンにするとGL_INVALID_OPERATION
、特に、に関するより実質的な情報が得られましたThe current operation is illegal in the current state: Buffer is mapped.
。だから私は上記のポイント1にぶつかっています。どうすればいいのかわかりませんが。
glMapBuffer
コードのどこにも、、または関連する関数の呼び出しはありません。、、、、およびへglMapBuffer
の呼び出しで中断するようにgDEBuggerを設定しましたが、どこでも中断しませんでした。次に、最初にコードを追加して、煩わしいバッファを明示的にマップ解除しました。エラーが消えなかっただけでなく、両方を呼び出すとが生成されます。それで、私が使用しているバッファのどちらもマップされていない場合、エラーはどこから来ていますか?glMapBufferARB
glMapBufferRange
glUnmapBuffer
glUnmapBufferARB
RenderPass1
glUnmapBuffer
The current operation is illegal in the current state: Buffer is unbound or is already unmapped.
8/19 / 12、午前12時に編集:
gDEBuggerのGLExpertから表示されるエラーメッセージに基づくと、呼び出しによってglBeginTransformFeedback
、バインドされたバッファGL_TRANSFORM_FEEDBACK_BUFFER
がマップされるようになっているようです。具体的には、「テクスチャ、バッファ、画像ビューア」でバッファをクリックすると、メッセージが出力されますThe current operation is illegal in the current state: Buffer must be bound and not mapped.
。ただし、これをとの間に追加するglBeginTransformFeedback
とglEndTransformFeedback
:
int bufferBinding;
glGetBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_MAPPED, &bufferBinding);
printf("Transform feedback buffer binding: %d\n", bufferBinding);
0を出力します。これは、GL_TRANSFORM_FEEDBACK_BUFFER
マップされていないことを示します。このバッファが別のバインディングポイントにマップされている場合でも、これは0を返しますか?なぜglBeginTransformFeedback
バッファをマップして、変換フィードバックに使用できないようにするのでしょうか。
ここで学べば学ぶほど、混乱していきます。
10/10/12を編集:
以下のNicolBolasの解決策への返信に示されているように、私は問題を見つけました。それは彼が見つけたものと同じです。愚かなタイプミスのため、同じバッファーを入力と出力の両方のバインドポイントにバインドしていました。
質問を投稿してからおそらく2週間後に見つかりました。私はしばらくの間欲求不満をあきらめ、最終的に戻ってきて、基本的にすべてを最初から再実装し、古い、機能していないものを定期的に比較しました。私が終わったとき、新しいバージョンは機能しました、そして私が間違ったバッファをバインドしていたことを発見したのは違いを調べたときでした。