什么可能导致glDrawArrays生成GL_INVALID_OPERATION错误?

时间:2012-08-18 08:36:04

标签: opengl glsl shader geometry-shader marching-cubes

我一直在尝试使用OpenGL和GLSL编写Marching Cubes算法的两遍GPU实现,类似于GPU Gems 3第一章中详细介绍的算法。但是,第一次传递中对glDrawArrays的调用始终以GL_INVALID_OPERATION失败。

我已查找了我能找到的所有文档,并发现glDrawArrays可能导致该错误的条件:

    如果将非零缓冲区对象名称绑定到已启用的数组或GL_INVALID_OPERATION绑定并且当前映射了缓冲区对象的数据存储,则会生成
  1. GL_DRAW_INDIRECT_BUFFER
  2. 如果在执行GL_INVALID_OPERATION和相应的glDrawArrays之间执行glBegin,则会生成
  3. glEnd
  4. GL_INVALID_OPERATION将由glDrawArraysglDrawElements生成,如果当前程序对象中的任何两个活动采样器具有不同类型,但引用相同的纹理图像单元。
  5. 如果几何着色器处于活动状态且模式与当前安装的程序对象中几何着色器的输入基元类型不兼容,则会生成
  6. GL_INVALID_OPERATION
  7. 如果模式为GL_INVALID_OPERATION并且没有曲面细分控件着色器处于活动状态,则会生成
  8. GL_PATCHES
  9. 如果将基元的顶点记录到用于变换反馈目的的缓冲区对象,则会生成
  10. GL_INVALID_OPERATION,这将导致超出任何缓冲区对象大小的限制,或超出结束位置偏移+大小 - 1,由glBindBufferRange设置。
  11. GL_INVALID_OPERATIONglDrawArrays()生成,如果没有几何着色器,则转换反馈处于活动状态且模式不是允许的模式之一。
  12. {li> GL_INVALID_OPERATIONglDrawArrays()生成,如果存在几何着色器,则变换反馈处于活动状态,并且几何着色器的输出基本类型与变换反馈primitiveMode不匹配。 如果绑定的着色器程序无效,则会生成
  13. GL_INVALID_OPERATION
  14. 如果正在使用转换反馈,则会生成
  15. EDIT 10/10/12: GL_INVALID_OPERATION,并且绑定到转换反馈绑定点的缓冲区也会绑定到数组缓冲区绑定点。 这是我遇到的问题,因为我绑定了缓冲区的拼写错误。虽然规范确实声明这是非法的,但在我发现的任何文档中,它都没有列在glDrawArrays下,因为它可能引发错误。
  16. 不幸的是,我找不到任何一份官方文档,其中包含超过3篇。我不得不从众多来源收集这份清单。第7点和第8点实际上来自glBeginTransformFeedback的文档,第9点似乎根本没有记录。我发现它在某个论坛帖子中提到过。但是,我仍然不认为这个列表是完整的,因为这些似乎都没有解释我得到的错误。

    1. 我没有在我的程序中随处映射任何缓冲区。
    2. 我使用的是Core配置文件,因此glBeginglEnd甚至无法使用。
    3. 我有两个采样器,它们有不同的类型,但它们肯定会映射到不同的纹理。
    4. 几何着色器处于活动状态,但它的输入布局为layout (points) inglDrawArrays正在调用GL_POINTS
    5. 我没有使用GL_PATCHES或任何类型的曲面细分着色器。
    6. 我已经确定我分配了几何着色器可能输出的最大空间量。然后我尝试了四倍。没有帮助。
    7. 有一个几何着色器。见下一点。
    8. 正在使用变换反馈,并且有一个几何着色器,但输出布局为layout (points) outglBeginTransformFeedback调用GL_POINTS
    9. 我在调用glValidateProgram之前尝试插入glDrawArrays来电,并返回GL_TRUE
    10. 实际的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的调用。值得注意的是,如果我注释掉glBeginTransformFeedbackglEndTransformFeedback的来电,则glDrawArrays会停止生成错误。无论如何,它可能与变换反馈有某种关系。

      编辑8/18 / 12,9:PM:

      我刚刚在gDEBugger中找到了NVIDIA GLExpert功能,我之前并不熟悉它。当我启用此功能时,它会在GL_INVALID_OPERATION上提供更多实质性信息,特别是The current operation is illegal in the current state: Buffer is mapped.。所以我跑到了上面的第1点。虽然我不知道怎么做。

      我的代码中的任何地方都没有调用glMapBuffer或任何相关函数。我设置gDEBugger以打破对glMapBufferglMapBufferARBglMapBufferRangeglUnmapBufferglUnmapBufferARB的任何调用,并且它并没有在任何地方中断。然后我将代码添加到RenderPass1的开头,以显式取消映射麻烦的缓冲区。错误不仅没有消失,而且glUnmapBuffer的调用现在都生成The current operation is illegal in the current state: Buffer is unbound or is already unmapped.。因此,如果我使用的缓冲区都没有映射,那么错误来自哪里?

      编辑2012年8月19日,上午12点:

      根据我在gDEBugger中退出GLExpert的错误消息,调用glBeginTransformFeedback似乎导致绑定到GL_TRANSFORM_FEEDBACK_BUFFER的缓冲区被映射。具体来说,当我点击&#34; Textures,Buffers and Images Viewer&#34;它输出消息The current operation is illegal in the current state: Buffer must be bound and not mapped.。但是,如果我在glBeginTransformFeedbackglEndTransformFeedback之间添加:

      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:

      正如我在下面的回复中指出的Nicol Bolas&#39;解决方案,我发现了问题,它与他发现的问题相同:由于一个愚蠢的错字,我将相同的缓冲区绑定到输入和输出绑定点。

      我发现可能在发布问题后两周。我沮丧地放弃了一段时间,并最终回来并基本上从头开始重新实现整个事情,定期比较旧的,不工作的一点点零碎。当我完成后,新版本起作用了,当我搜索出我发现的差异时,我已经绑定了错误的缓冲区。

3 个答案:

答案 0 :(得分:18)

我发现了你的问题:你正在渲染到你正在寻找顶点数据的缓冲区。

  

glBindVertexArray(vaoPass2);

我认为你的意思是vaoPass1

来自规范:

  

缓冲区不应该被绑定或用于变换反馈和其他   GL中的目的。具体来说,如果缓冲区对象同时绑定到a   转换反馈缓冲区绑定点和GL中的其他位置,任何写入   或从缓冲区读取生成未定义的值。这种绑定的例子   包括ReadPixels到像素缓冲区对象绑定点和客户端访问a   用MapBuffer映射的缓冲区。

现在,您应该获得未定义的值;我不确定GL错误是否合格,但可能应该是错误。

答案 1 :(得分:7)

glDrawArraysglDrawElementsGL_INVALID_OPERATION而失败的另一个(显然未记录的)案例:

    如果将采样器均匀设置为无效纹理单元标识符,则会生成
  • GL_INVALID_OPERATION。 (当我的意思是glUniform1i(location, GL_TEXTURE0);时,我错误地执行了glUniform1i(location, 0);。)

答案 2 :(得分:1)

另一个(未记录的)案例wp_enqueue_style( 'revolution_settings', get_stylesheet_directory_uri() . '/js/revolution/css/settings.css' ); wp_enqueue_style( 'revolution_layers', get_stylesheet_directory_uri() . '/js/revolution/css/layers.css' ); wp_enqueue_style( 'revolution_navigation', get_stylesheet_directory_uri() . '/js/revolution/css/navigation.css' ); wp_enqueue_script( 'revolutiontools_js', get_template_directory_uri() . '/js/revolution/js/jquery.themepunch.tools.min.js', array('jquery'), '1.11.1', false); wp_enqueue_script( 'revolution_js', get_template_directory_uri() . '/js/revolution/js/jquery.themepunch.revolution.min.js', array('jquery'), '1.11.1', false); 调用可能会因<script> jQuery(document).ready(function() { jQuery('#rev_slider_1').show().revolution({ /* options are 'auto', 'fullwidth' or 'fullscreen' */ sliderLayout: 'auto', /* basic navigation arrows and bullets */ navigation: { arrows: { enable: true, style: 'hesperiden', hide_onleave: false }, bullets: { enable: true, style: 'hesperiden', hide_onleave: false, h_align: 'center', v_align: 'bottom', h_offset: 0, v_offset: 20, space: 5 } } }); }); 而失败:

    如果将采样器均匀设置为绑定到不正确类型的纹理的纹理单元,则会生成
  • glDraw*()。例如,如果GL_INVALID_OPERATION设置为GL_INVALID_OPERATION,但uniform sampler2D的纹理绑定为glUniform1i(location, 0);