为什么GL.EnableVertexArrayAttrib在计算机上崩溃而不在另一台计算机上崩溃?

时间:2020-06-29 21:49:11

标签: c# opengl opentk

我正在使用OpenTK,这是​​C#的OpenGL库。我在主PC(Nvidia视频卡)上启动了一个项目,一切都很好。然后我将其继续放在笔记本电脑(AMD视频卡)上,调用GL.EnableVertexArrayAttrib时出现异常。

用于复制的最小代码:

// Create a shader with a `test` attribute
int vertexShaderID = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertexShaderID, "in vec3 test; void main() { gl_Position = vec4(0, 0, 0, 0); }");
GL.CompileShader(vertexShaderID);
int fragmentShaderID = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragmentShaderID, "void main() { gl_FragColor = vec4(0, 0, 0, 0); }");
GL.CompileShader(fragmentShaderID);
int programID = GL.CreateProgram();
GL.UseProgram(programID);
GL.AttachShader(programID, vertexShaderID);
GL.AttachShader(programID, fragmentShaderID);
GL.LinkProgram(programID);

// Make a VAO, get the `test` attribute location and enable it
int vao = GL.GenVertexArray();
int attrib = GL.GetAttribLocation(programID, "test");
GL.EnableVertexArrayAttrib(vao, attrib); // Throws AccessViolationException on AMD, but not on NVIDIA

我在Windows 8.1 AMD笔记本电脑上拥有最新的GPU驱动程序和最新的OpenTK。

1 个答案:

答案 0 :(得分:1)

您正在将4.5个直接状态访问(DSA)调用与3.3个调用混合使用,不要这样做,只会导致此类错误。

问题在于3.3 glGen*和4.5 glCreate*函数之间的行为存在细微差别。 glGen*版本仅为对象保留一个位置,但是将其创建推迟到使用glBind*首次绑定对象时。我不确定为什么要这样决定。无论如何,这通常并不重要,因为必须先绑定对象才能对其进行任何处理。至少在DSA成为现实之前是这样。 因此,您的VAO从未绑定,因此也从未创建,也没有启用的功能。

有两种方法可以修复程序:

  1. 致力于使用OpenGL 4.5功能。它们使用起来更舒适,不需要glBind*调用就只调用下一个函数,它更像方法。另外,很少有新功能可以为您提供更细粒度的控制-explicit uniform locations(4.3+)也很不错。不是新的,所有现代GPU都支持它。虽然不确定旧的控制台或移动设备,但我也知道VirtualBox VM限于3.3。

    在这种情况下,您要做的就是使用 CreateVertexArray CreateVertexArrays函数创建VAO。

    int vao;
    GL.CreateVertexArrays(1,out vao);
    int attrib = GL.GetAttribLocation(programID, "test");
    GL.EnableVertexArrayAttrib(vao, attrib);
    

    您也可能至少打过一次glBind*,但请不要依赖它,这对将来的读者来说并不明显。

  2. 使用3.3并使用EnableVertexAttribArray而不是EnableVertexArrayAttrib。是的,这是一个非常糟糕的命名决定,很有可能背叛了您的代码补全,然后您就填写了适当的参数。此功能更改当前绑定的VAO的状态。

     int vao = GL.GenVertexArray();
     int attrib = GL.GetAttribLocation(programID, "test");
     GL.BindVertexArray(vao); //Only here is the actual VAO with 'vao' handle created.
     GL.EnableVertexAttribArray(attrib); // Changes currently the bound VAO's state.
    

关于它在NVIDIA上运行的原因? OpenGL驱动程序一团糟。他们尝试预见并纠正常见错误-例如在核心中没有绑定VAO的绘图,缺少索引缓冲区,超出范围的绘图调用,合理的默认位置,采样器或着色器中的一些细微错误。严重依赖隐藏的全局上下文状态根本没有帮助。我个人的经验是,NVIDIA往往是最宽容的,AMD是50-50,英特尔是最严格的。如果可以的话,我建议同时同时在集成卡和专用卡上进行开发。在一张卡上同时出现黑屏而另一张卡上却出现黑屏,并想知道最近X个小时中的哪些变化可能是原因,这并没有令人高兴。