gpt4 book ai didi

opengl - 什么会导致 glDrawArrays 产生 GL_INVALID_OPERATION 错误?

转载 作者:行者123 更新时间:2023-12-03 01:13:18 26 4
gpt4 key购买 nike

我一直在尝试编写 Marching Cubes 算法的两次 GPU 实现,类似于 GPU Gems 3 第一章中详述的那个,使用 OpenGL 和 GLSL。然而,拨打glDrawArrays在我的第一遍中,始终以 GL_INVALID_OPERATION 失败.

我查阅了所有我能找到的文档,并找到了这些条件 glDrawArrays可以抛出该错误:

  • GL_INVALID_OPERATION如果非零缓冲区对象名称绑定(bind)到启用的数组或 GL_DRAW_INDIRECT_BUFFER,则生成绑定(bind)和缓冲区对象的数据存储当前已映射。
  • GL_INVALID_OPERATION如果 glDrawArrays 生成在 glBegin 的执行之间执行和相应的 glEnd .
  • GL_INVALID_OPERATION将由 glDrawArrays 生成或 glDrawElements如果当前程序对象中的任意两个事件采样器类型不同,但引用相同的纹理图像单元。
  • GL_INVALID_OPERATION如果几何着色器处于事件状态并且模式与当前安装的程序对象中几何着色器的输入基元类型不兼容,则会生成。
  • GL_INVALID_OPERATION如果模式为 GL_PATCHES,则生成并且没有曲面分割控制着色器处于事件状态。
  • GL_INVALID_OPERATION如果将图元的顶点记录到用于变换反馈目的的缓冲区对象将导致超出任何缓冲区对象大小的限制,或超出结束位置偏移量 + 大小 - 1(由 glBindBufferRange 设置),则会生成.
  • GL_INVALID_OPERATIONglDrawArrays() 生成如果不存在几何着色器,则变换反馈处于事件状态,并且模式不是允许的模式之一。
  • GL_INVALID_OPERATIONglDrawArrays() 生成如果存在几何着色器,则变换反馈处于事件状态,并且几何着色器的输出基元类型与变换反馈基元模式不匹配。
  • GL_INVALID_OPERATION如果绑定(bind)的着色器程序无效,则生成。
  • 编辑 10/10/12: GL_INVALID_OPERATION如果正在使用变换反馈,则生成,并且绑定(bind)到变换反馈绑定(bind)点的缓冲区也绑定(bind)到数组缓冲区绑定(bind)点。 这是我遇到的问题,因为我绑定(bind)的缓冲区打错了。虽然规范确实声明这是非法的,但在我找到的任何文档中,它都没有列在 glDrawArrays 下作为它可能引发错误的原因之一。

  • 不幸的是,我找不到任何一份官方文档涵盖其中的 3 个以上。我不得不从众多来源收集这份 list 。第 7 点和第 8 点实际上来自 glBeginTransformFeedback 的文档。 ,第 9 点似乎根本没有记录。我在某处的论坛帖子中发现了它。但是,我仍然不认为这个列表是完整的,因为这些似乎都不能解释我得到的错误。
  • 我没有在我的程序中的任何地方映射任何缓冲区。
  • 我正在使用 Core 配置文件,所以 glBeginglEnd甚至不可用。
  • 我有两个采样器,它们的类型不同,但它们肯定映射到不同的纹理。
  • 几何着色器处于事件状态,但其输入布局为 layout (points) in , 和 glDrawArrays正在用 GL_POINTS 调用.
  • 我没有使用 GL_PATCHES或任何类型的曲面分割着色器。
  • 我确保我分配了几何着色器可能输出的最大空间量。然后我尝试将它翻两番。没有帮助。
  • 有一个几何着色器。看下一点。
  • 正在使用变换反馈,并且有几何着色器,但输出布局为layout (points) outglBeginTransformFeedbackGL_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);
    }

    实际错误是调用 glDrawArraysRenderPass1 .值得注意的是,如果我注释掉对 glBeginTransformFeedback 的调用和 glEndTransformFeedback ,然后 glDrawArrays停止生成错误。因此,无论出现什么问题,都可能与转换反馈有某种关系。

    编辑 8/18/12,晚上 9 点:

    我刚刚在 gDEBugger 中发现了 NVIDIA GLExpert 功能,这是我以前不熟悉的。当我打开它时,它提供了更多关于 GL_INVALID_OPERATION 的信息。 ,特别是 The current operation is illegal in the current state: Buffer is mapped. .所以我遇到了上面的第 1 点。虽然我不知道如何。

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

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

    根据我在 gDEBugger 中退出 GLExpert 的错误消息,似乎调用 glBeginTransformFeedback导致缓冲区绑定(bind)到 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未映射。如果这个缓冲区被映射到另一个绑定(bind)点,这仍然返回 0 吗?为什么会 glBeginTransformFeedback映射缓冲区,从而使其无法用于转换反馈?

    我在这里学到的越多,我就越困惑。

    编辑 10/10/12:

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

    我可能是在发布问题两周后发现的。我沮丧地放弃了一段时间,最终回来并基本上从头开始重新实现了整个事情,定期比较旧的、非工作的点点滴滴。当我完成后,新版本就可以工作了,当我找出差异时,我发现我绑定(bind)了错误的缓冲区。

    最佳答案

    我想出了你的问题:你渲染到你正在获取顶点数据的同一个缓冲区。

    glBindVertexArray(vaoPass2);



    我想你的意思是 vaoPass1
    从规范:

    Buffers should not be bound or in use for both transform feedback and other purposes in the GL. Specifically, if a buffer object is simultaneously bound to a transform feedback buffer binding point and elsewhere in the GL, any writes to or reads from the buffer generate undefined values. Examples of such bindings include ReadPixels to a pixel buffer object binding point and client access to a buffer mapped with MapBuffer.



    现在,您应该得到未定义的值;我不确定 GL 错误是否符合条件,但它可能应该是一个错误。

    关于opengl - 什么会导致 glDrawArrays 产生 GL_INVALID_OPERATION 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12017175/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com