我正在使用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。
答案 0 :(得分:1)
您正在将4.5个直接状态访问(DSA)调用与3.3个调用混合使用,不要这样做,只会导致此类错误。
问题在于3.3 glGen*
和4.5 glCreate*
函数之间的行为存在细微差别。 glGen*
版本仅为对象保留一个位置,但是将其创建推迟到使用glBind*
首次绑定对象时。我不确定为什么要这样决定。无论如何,这通常并不重要,因为必须先绑定对象才能对其进行任何处理。至少在DSA成为现实之前是这样。 因此,您的VAO从未绑定,因此也从未创建,也没有启用的功能。
有两种方法可以修复程序:
致力于使用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*
,但请不要依赖它,这对将来的读者来说并不明显。
使用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个小时中的哪些变化可能是原因,这并没有令人高兴。