I just updated from my shitty ASUS drivers to actually working, non-crashing, non-flickering video drivers from Nvidia. However, this broke about half of my games and tests. The problem only occurs in OpenGL 3 games that use buffers but do not use Vertex Array objects for the shader attribute mapping (glVertexAttribPointer and glEnableVertexAttribArray). I tried to reproduce the problem in a small test program, but that test works both with and without VAOs. I am so confused about it. I managed to reproduce it. See the bottom of this post.
The fact remains that my main project is affected by this (in an “it worked before, but not anymore” way). As Nvidia is known for bending rules in GLSL with automatic casting e.t.c. could this be something similar? Do I HAVE to use VAOs? Is it illegal to call VertexAttrib functions without a VAO binded? It’s the only thing I can think of that could be “fixed” between two drivers.
I’ve created a small program to show what happens. (It didn’t work at first because I was using a backwards compatible context.) Just copy this into a class, add the LWJGL library, setup the LWJGL natives and run it. Should open a window and render a colored triangle in the top right quadrant of the window.
REQUIRES: an OpenGL 3.2 ( = DirectX 10 compatible) compatible video card. If you have an OpenGL 3.2 compatible card but it doesn’t work, update your drivers.
To switch on and off VAOs, change the constant USE_VAO.
Here is the code:
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.PixelFormat;
public class VAOTest {
private static final boolean USE_VAO = false;
private void run() throws Exception {
//Display setup
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create(new PixelFormat(), new ContextAttribs(3, 2).withProfileCompatibility(false));
//Vertex shader
int vertexShader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
GL20.glShaderSource(vertexShader, getVertexShaderSource());
GL20.glCompileShader(vertexShader);
String vertexShaderErrorLog = GL20.glGetShaderInfoLog(vertexShader, 65536);
if (vertexShaderErrorLog.length() != 0) {
System.err.println("Vertex shader compile log: \n" + vertexShaderErrorLog);
}
//Fragment shader
int fragmentShader = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
GL20.glShaderSource(fragmentShader, getFragmentShaderSource());
GL20.glCompileShader(fragmentShader);
String fragmentShaderErrorLog = GL20.glGetShaderInfoLog(fragmentShader, 65536);
if (fragmentShaderErrorLog.length() != 0) {
System.err.println("Fragment shader compile log: \n" + fragmentShaderErrorLog);
}
//Shader program
int program = GL20.glCreateProgram();
GL20.glAttachShader(program, vertexShader);
GL20.glAttachShader(program, fragmentShader);
GL20.glLinkProgram(program);
String log = GL20.glGetProgramInfoLog(program, 65536);
if (log.length() != 0) {
System.err.println("Program link log:\n" + log);
}
//Get vertex location
int vertexLocation = GL20.glGetAttribLocation(program, "inVertex");
if (vertexLocation == -1) {
System.err.println("SHADER ERROR: Attribute 'inVertex' does not exist!");
}
int colorLocation = GL20.glGetAttribLocation(program, "inColor");
if (colorLocation == -1) {
System.err.println("SHADER ERROR: Attribute 'inColor' does not exist!");
}
//Create vertex data
FloatBuffer vertexData = BufferUtils.createFloatBuffer(5 * 3);
vertexData.put(new float[]{
//x, y, r, g, b
0, 0, 1, 0, 0, //1st vertex
1, 0, 0, 1, 0, //2nd
0, 1, 0, 0, 1 //3rd
});
vertexData.flip();
//Create index data
ShortBuffer indexData = BufferUtils.createShortBuffer(3);
indexData.put(new short[]{0, 1, 2});
indexData.flip();
//Buffer creation and loading
int vertexBuffer = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBuffer);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexData, GL15.GL_STATIC_DRAW);
int indexBuffer = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indexData, GL15.GL_STATIC_DRAW);
//Setup VAO if needed
int vao = -1;
if (USE_VAO) {
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBuffer); //Already binded, but whatever...
GL20.glVertexAttribPointer(vertexLocation, 2, GL11.GL_FLOAT, false, 5 * 4, 0);
GL20.glEnableVertexAttribArray(vertexLocation);
GL20.glVertexAttribPointer(colorLocation, 3, GL11.GL_FLOAT, false, 5 * 4, 2 * 4);
GL20.glEnableVertexAttribArray(colorLocation);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
GL30.glBindVertexArray(0); //Unbind
}
//Clear color
GL11.glClearColor(0, 0, 0, 0);
while (!Display.isCloseRequested()) {
//Clear screen
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
//Enable shader
GL20.glUseProgram(program);
//Either use VAO or enable vertex attributes manually
if (USE_VAO) {
GL30.glBindVertexArray(vao);
} else {
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBuffer);
GL20.glVertexAttribPointer(vertexLocation, 2, GL11.GL_FLOAT, false, 5 * 4, 0);
GL20.glEnableVertexAttribArray(vertexLocation);
GL20.glVertexAttribPointer(colorLocation, 3, GL11.GL_FLOAT, false, 5 * 4, 2 * 4);
GL20.glEnableVertexAttribArray(colorLocation);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
}
int error = GL11.glGetError();
if (error != 0) {
System.out.println("OpenGL error '" + error + "' occured!");
}
//Draw triangle
GL11.glDrawElements(GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_SHORT, 0);
Display.update();
}
}
public static void main(String[] args) throws Exception {
new MiniTest().run();
}
public String getVertexShaderSource() {
return "#version 330\n"
+ "in vec2 inVertex;"
+ "in vec3 inColor;"
+ "out vec3 fColor;"
+ "void main(){"
+ "gl_Position = vec4(inVertex, 0, 1);"
+ "fColor = inColor;"
+ "}";
}
public String getFragmentShaderSource() {
return "#version 330\n"
+ "in vec3 fColor;"
+ "layout(location = 0) out vec4 fragColor;"
+ "void main(){"
+ "fragColor = vec4(fColor, 1);"
+ "}";
}
}
Tested with a NVidia GTX 460M. Only works with USE_VAO set to true for me. Would be awesome if somebody with a Radeon card could try this too.