Co może spowodować, że program glDrawArrays wygeneruje nieprawidłowy błąd operacji GL?
Próbowałem napisać dwuprzebiegową implementację GPU algorytmu Marching Cubes, podobną do tej opisanej w pierwszym rozdziale GPU Gems 3, używając OpenGL i GLSL. Jednak wezwanie do glDrawArrays
w moim pierwszym przejściu konsekwentnie zawodzi z GL_INVALID_OPERATION
.
Przejrzałem całą dokumentację, którą mogę znaleźć, i znalazłem te warunki, w których glDrawArrays
może wyrzucić ten błąd:
-
GL_INVALID_OPERATION
jest generowane, jeśli niezerowa nazwa obiektu bufora jest powiązana z włączoną tablicą lub do powiązaniaGL_DRAW_INDIRECT_BUFFER
i magazyn danych obiektu bufora jest obecnie mapowany. -
GL_INVALID_OPERATION
jest generowane, jeśli {[2] } jest wykonywane pomiędzy wykonaniemglBegin
a odpowiadającym muglEnd
. -
GL_INVALID_OPERATION
zostanie wygenerowane przezglDrawArrays
lubglDrawElements
, Jeśli dowolne dwa aktywne samplery w bieżącym obiekcie programu są różnych typów, ale odnoszą się do tej samej jednostki obrazu tekstury. -
GL_INVALID_OPERATION
jest generowany, jeśli aktywny jest shader geometry i tryb jest niezgodny z typem wejściowym geometry shader w aktualnie zainstalowanym obiekcie programu. -
GL_INVALID_OPERATION
jest generowane, jeśli tryb jestGL_PATCHES
i nie jest aktywny żaden shader kontrolny teselacji. -
GL_INVALID_OPERATION
jest generowane, jeśli zapis wierzchołków prymitywnych obiektów bufora używanych do celów sprzężenia zwrotnego transformacji spowodowałby przekroczenie granic rozmiaru dowolnego obiektu bufora lub przekroczenie przesunięcia położenia końcowego + Rozmiar-1, Jak określono przezglBindBufferRange
. -
GL_INVALID_OPERATION
jest generowane przezglDrawArrays()
jeśli nie ma geometrii shader jest obecny, sprzężenie zwrotne transformacji jest aktywne, a tryb nie jest jednym z dozwolonych trybów. -
GL_INVALID_OPERATION
jest generowane przezglDrawArrays()
jeśli obecny jest shader geometry, sprzężenie zwrotne transformacji jest aktywne, a wyjściowy prymitywny Typ shader geometry nie pasuje do primitivemode sprzężenia zwrotnego transformacji. -
GL_INVALID_OPERATION
jest generowane, jeśli program bound shader jest nieprawidłowy. -
edytuj 10/10/12:
GL_INVALID_OPERATION
jest generowany, jeśli w użyciu jest sprzężenie zwrotne transformacji, a bufor związany z punkt wiązania sprzężenia zwrotnego transformacji jest również związany z punktem wiązania bufora tablicy. to jest problem, który miałem, ze względu na literówkę, w którym buforze powiązałem. Podczas gdy spec stwierdza, że jest to nielegalne, nie jest wymieniony w glDrawArrays jako jeden z powodów, dla których może rzucić błąd w dowolnej dokumentacji, którą znalazłem.
Niestety, żaden fragment oficjalnej dokumentacji nie może znaleźć obejmuje więcej niż 3 z nich. Musiałem zebrać tę listę z wielu źródeł. Punkty 7 i 8 rzeczywiście pochodzi z dokumentacji glBeginTransformFeedback
, A punkt 9 nie wydaje się być w ogóle udokumentowany. Znalazłem to gdzieś w poście na forum. Jednak nadal nie sądzę, aby ta lista była kompletna, ponieważ żadna z nich nie wyjaśnia błędu, który otrzymuję.
- nie mapuję żadnych buforów w moim programie, nigdzie.
- używam głównego profilu, więc
glBegin
iglEnd
nie są nawet dostępne.
[66]}mam dwa samplery, i są one różnych typów, ale są zdecydowanie odwzorowane na różne tekstury.
- Shader geometrii jest aktywny, ale jego układ wejściowy to
layout (points) in
, aglDrawArrays
jest wywoływany przezGL_POINTS
. - nie używam
GL_PATCHES
ani żadnych shaderów teselacji. - upewniłem się, że przydzielam maksymalną ilość miejsca, jaką mogą uzyskać shadery geometrii. Potem próbowałem go poczwórnie zestawić. Nie pomogło.
- istnieje Shader geometrii. Zobacz następny punkt.
- transformacja sprzężenia zwrotnego jest używana, a istnieje shader geometrii, ale układ wyjściowy to
layout (points) out
, a {[25] } jest wywoływany przezGL_POINTS
. - próbowałem wstawić połączenie do
glValidateProgram
tuż przed połączeniem doglDrawArrays
, i zwróciłoGL_TRUE
.
Rzeczywisty kod OpenGL jest tutaj:
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);
}
Prawdziwym błędem jest wywołanie glDrawArrays
w RenderPass1
. Warto zauważyć, że jeśli skomentuję wywołania do glBeginTransformFeedback
i glEndTransformFeedback
, to glDrawArrays
przestaje generować błąd. Więc cokolwiek jest nie tak, prawdopodobnie jest to w jakiś sposób związane z transformacją informacje zwrotne.
Edit 8/18/12, 9 PM:
Właśnie znalazłem funkcję NVIDIA GLExpert w gdebuggerze, z którą wcześniej nie byłem zaznajomiony. Kiedy to włączyłem, dało to nieco bardziej istotne informacje na temat GL_INVALID_OPERATION
, a konkretnie The current operation is illegal in the current state: Buffer is mapped.
. Więc wpadam do punktu 1, powyżej. Chociaż nie mam pojęcia jak.
Nie mam żadnych wywołań do glMapBuffer
, ani żadnej powiązanej funkcji, gdziekolwiek w moim kodzie. Ustawiłem gDEBugger na Łamanie wszelkich połączeń do glMapBuffer
, glMapBufferARB
, glMapBufferRange
, glUnmapBuffer
oraz glUnmapBufferARB
, i nigdzie się nie złamał. Następnie dodałem kod na początku RenderPass1
, aby jawnie odmapować bufory. Nie tylko błąd nie zniknął, ale wywołania {[49] } teraz oba generują The current operation is illegal in the current state: Buffer is unbound or is already unmapped.
. Więc jeśli żaden z buforów, których używam, nie jest zmapowany, skąd pochodzi błąd?
Edit 8/19/12, 12: 00:
Na podstawie komunikatów o błędach, które otrzymuję z GLExpert w gdebuggerze, wydaje się, że wywołanie glBeginTransformFeedback
powoduje, że bufor związany z GL_TRANSFORM_FEEDBACK_BUFFER
zostaje zmapowany. W szczególności, gdy klikam na bufor w "Texttures, Buffers and Images Viewer"wyświetla komunikat The current operation is illegal in the current state: Buffer must be bound and not mapped.
. Jeśli jednak dodam to między glBeginTransformFeedback
A glEndTransformFeedback
:
int bufferBinding;
glGetBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_MAPPED, &bufferBinding);
printf("Transform feedback buffer binding: %d\n", bufferBinding);
Wyświetla 0, co wskazywałoby, że GL_TRANSFORM_FEEDBACK_BUFFER
nie jest mapowana. Jeśli ten bufor jest mapowany w innym punkcie wiązania, czy to nadal zwróci 0? Dlaczego glBeginTransformFeedback
zmapowałby bufor, czyniąc go bezużytecznym dla sprzężenia zwrotnego transformacji?
Edytuj 10/10/12:
Jak wskazano w mojej Odpowiedzi poniżej na rozwiązanie Nicola Bolasa, znalazłem problem i jest to ten sam, który znalazł: z powodu głupiej literówki, wiązałem ten sam bufor zarówno do wejścia, jak i wyjścia.
Znalazłem go prawdopodobnie dwa tygodnie po wysłaniu pytania. Poddałem się frustracji na jakiś czas, a w końcu wróciłem i w zasadzie odtworzyłem całość od zera, regularnie porównując kawałki i kawałki starszego, niedziałającego. Kiedy skończyłem, nowa wersja zadziałała, i to było, gdy szukałem różnic, które odkryłem, że wiązałem zły bufor.
3 answers
Rozgryzłem twój problem: renderujesz do tego samego bufora, w którym pozyskujesz dane wierzchołków.
GlBindVertexArray (vaoPass2);
Myślę, że miałeś na myśli vaoPass1
Od spec:
Bufory nie powinny być związane ani używane zarówno dla sprzężenia zwrotnego transformatora, jak i innych cele w GL. W szczególności, jeśli obiekt bufora jest jednocześnie związany z przekształcić punkt wiązania bufora sprzężenia zwrotnego i gdzie indziej w GL, każdy zapis do lub czyta z bufora generuje niezdefiniowane wartości. Przykłady takich wiązań zawierać Readpixele do punktu wiązania obiektu bufora pikseli i dostęp Klienta do bufor mapowany za pomocą Mapbuffera.
Teraz powinieneś uzyskać wartości niezdefiniowane; nie jestem pewien, czy błąd GL kwalifikuje się, ale prawdopodobnie powinien to być błąd.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-10 21:35:38
Kolejny (pozornie nieudokumentowany) przypadek, w którym glDrawArrays
i glDrawElements
nie powiodą się z GL_INVALID_OPERATION
:
-
GL_INVALID_OPERATION
jest generowane, jeśli uniform próbnika jest ustawiony na nieprawidłowy identyfikator jednostki tekstury. (Omyłkowo wykonałemglUniform1i(location, GL_TEXTURE0);
, Kiedy miałem na myśliglUniform1i(location, 0);
.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-29 19:19:37
Kolejny (nieudokumentowany) przypadek, w którym glDraw*()
wywołania mogą się nie udać za pomocą GL_INVALID_OPERATION
:
-
GL_INVALID_OPERATION
jest generowane, jeśli jednolita próbka jest ustawiona na jednostkę tekstury powiązaną z teksturą nieprawidłowego typu. Na przykład, jeśliuniform sampler2D
jest ustawioneglUniform1i(location, 0);
, aleGL_TEXTURE0
ma teksturęGL_TEXTURE_2D_ARRAY
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-18 02:16:42