LWJGL 3 - OpenGL error while drawing triangle: 1282

Started by ShadowDragon, October 28, 2016, 19:34:26

Previous topic - Next topic

ShadowDragon

Hi,

I'm having quite a problem when drawing a simple triangle:
Quote
Debug message ( 1282 ): GL_INVALID_OPERATION error generated.
Source: API

Type: Error

Severity: high

EDITED:
Here is my code:
private long window;
	
	private int width, height;
	private String title;
	
	private Thread thread;
	private boolean running = false;
	
	public Game(int width, int height, String title) {
		this.width = width;
		this.height = height;
		this.title = title;
		this.start();
	}
	
	private synchronized void start() {
		this.running = true;
		this.thread = new Thread(this, "Test");
		this.thread.start();
		
		System.out.println("Initializing...");
		System.out.println("LWJGL " + Version.getVersion());
	}
	
	public synchronized void stop() {
		if(this.running) this.running = false;
		
		this.dispose();
		
		glfwFreeCallbacks(this.window);
		glfwDestroyWindow(this.window);
		
		glfwTerminate();
		glfwSetErrorCallback(null).free();
	}
	
	private boolean init() {
		GLFWErrorCallback.createPrint(System.err).set();
		
		if(!glfwInit())
			throw new IllegalStateException("Unable to initialize GLFW");
		
		glfwDefaultWindowHints();
		glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
		glfwWindowHint(GLFW_FOCUSED, GL_TRUE);
		glfwWindowHint(GLFW_SAMPLES , 4);
		glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
		
		this.window = glfwCreateWindow(this.width, this.height, this.title, NULL, NULL);
		if(window == NULL)
			throw new RuntimeException("Failed to create the GLFW window");
		
		GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
		
		glfwMakeContextCurrent(this.window);
		glfwSwapInterval(1);
		//glfwSwapInterval(0); disable v-sync... coming soon
		
		glfwShowWindow(this.window);
		GL.createCapabilities();
		glClearColor(0.f, 0.f, 0.f, 0.f);
		
		return true;
	}
	
	private String vertex_shader[] = {
			"#version 450 core \n",
			"\n",
			"void main(void) \n",
			"{ \n",
			"    const vec4 vertices[3] = vec4[3](vec4( .25, -.25, .5, 1.),  \n",
			"						              vec4(-.25, -.25, .5, 1.),  \n",
			"								      vec4( .25,  .25, .5, 1.)); \n",
			"\n",
			"    gl_Position = vertices[gl_VertexID]; \n",
			"}\n",
			"\n",
			"\n",
			"\n",
	};
	
	private String fragment_shader[] = {
			"#version 450 core \n",
			"\n",
			"out vec4 color; \n",
			"\n",
			"void main(void) \n",
			"{ \n",
			"    color = vec4(0.0, 0.8, 1.0, 1.0); \n",
			"} \n",
			"\n",
			"\n",
			"\n",
			"\n",
	};
	
	private Shader shader;
	
	private String arrayToString(Object[] a) {
		if(a == null)
			return "null";
		
		StringBuilder builder = new StringBuilder();
		for(Object s : a)
			builder.append(String.valueOf(s));
		
		System.out.println("--------------------------------------");
		System.out.println(builder.toString());
		System.out.println("--------------------------------------");
		
		return builder.toString();
	}
	
	public void run() {
		this.init();
		
		long lastTime = System.nanoTime();
		long timer = System.currentTimeMillis();
		final double ns = 1000000000.0 / 60;
		double delta = 0.d;
		int updates = 0;
		int frames = 0;
		int counter = 0;
		this.shader = new Shader();
		this.shader.compile(arrayToString(this.vertex_shader), arrayToString(this.fragment_shader), null);
		
		while(running) {
			long now = System.nanoTime();
			delta += (now - lastTime) / ns;
			lastTime = now;
			
			if(this.scene == null)
				throw new RuntimeException("Failed to update the scene. scene is null!");
			
			while(delta >= 1.d) {
				this.update();
				updates++;
				delta--;
			}
			this.render();
			frames++;
			
			if(System.currentTimeMillis() - timer > 1000) { // 1000 ms = 1s
				timer += 1000;
				System.out.println(updates + " ups, " + frames + " fps");
				updates = 0;
				frames = 0;
			}
			
			if(glfwWindowShouldClose(this.window)) this.running = false;
		}
		
		this.stop();
	}
	
	private void update() {
		glfwPollEvents();
	}
	
	private void render() {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		this.shader.use();
		
		glDrawArrays(GL_TRIANGLES, 0, 3);
		
		ErrorHandler.glCheckError(this.getClass().getName());
		
		glfwSwapBuffers(this.window);
	}


shader.use() does this here:
glUseProgram(this.ID);

ID is the ID of the program or what glCreateProgram returns.

Anyone who knows how to fix this and what is causing the problem?

Thx in advance.
ShadowDragon

Cornix

Check GL errors after every OpenGL command you call. When the first one creates the error look at the documentation to find out what it means. Hopefully this will help you now and in the future to understand your errors better.

ShadowDragon

Quote from: Cornix on October 28, 2016, 20:35:45
Check GL errors after every OpenGL command you call. When the first one creates the error look at the documentation to find out what it means. Hopefully this will help you now and in the future to understand your errors better.
Ok, thx. That's what I found to this:
QuoteGL_INVALID_OPERATION, 0x0502
Given when the set of state for a command is not legal for the parameters given to that command. It is also given for commands where combinations of parameters define what the legal parameters are.
https://www.opengl.org/wiki/OpenGL_Error

But I still don't know what's causing the problem.

Also I edited the main post a bit.
With a bit help from the eclipse debugger (setting a break-point at the error handler I'm getting this information:
--------------------------------------
#version 450 core 

void main(void) 
{ 
    const vec4 vertices[3] = vec4[3](vec4( .25, -.25, .5, 1.),  
						              vec4(-.25, -.25, .5, 1.),  
								      vec4( .25,  .25, .5, 1.)); 

    gl_Position = vertices[gl_VertexID]; 
}




--------------------------------------
--------------------------------------
#version 450 core 

out vec4 color; 

void main(void) 
{ 
    color = vec4(0.0, 0.8, 1.0, 1.0); 
} 





--------------------------------------
---------------
Debug message ( 1282 ): GL_INVALID_OPERATION error generated.
Source: API

Type: Error

Severity: high

0 ups, 1 fps
---------------
Debug message ( 1282 ): GL_INVALID_OPERATION error generated. Array object is not active.
Source: API

Type: Error

Severity: high

---------------
Debug message ( 1282 ): GL_INVALID_OPERATION error generated.
Source: API

Type: Error

Severity: high

639 ups, 1 fps
---------------
Debug message ( 1282 ): GL_INVALID_OPERATION error generated. Array object is not active.
Source: API

Type: Error

Severity: high

Cornix

As I said, you first have to find out which openGL method generates the error. If you dont know which line the error happens on you wont be able to fix it.
Then, when you know which command causes the problem, you can look up in the docs for that particular command to find out what the error means.

ShadowDragon

Quote from: Cornix on October 29, 2016, 06:58:14
As I said, you first have to find out which openGL method generates the error. If you dont know which line the error happens on you wont be able to fix it.
Then, when you know which command causes the problem, you can look up in the docs for that particular command to find out what the error means.
Hm, something is odd about this problem:
In the example code from the LWJGL 3 main page the triangle renders perfectly fine and in some other code I've got it
gives also the same error:
public class ProjectZTest {
	
	public static final int WIDTH = 800, HEIGHT = 600;
	
	// The window handle
	private long window;
	private IntBuffer screenWidth = BufferUtils.createIntBuffer(1), screenHeight = BufferUtils.createIntBuffer(1);
	
	public ProjectZTest() {
		System.out.println("LWJGL " + Version.getVersion());
		try {
			init();
			loop();
			
			// Free the window callbacks and destroy the window
			glfwFreeCallbacks(this.window);
			glfwDestroyWindow(this.window);
		} finally {
			// Terminate GLFW and free the error callback
			glfwTerminate();
			glfwSetErrorCallback(null).free();
		}
	}
	
	private String vertex_shader[] = {
			"#version 450 core \n",
			"\n",
			"void main(void) \n",
			"{ \n",
			"    const vec4 vertices[3] = vec4[3](vec4( .25, -.25, .5, 1.),  \n",
			"						              vec4(-.25, -.25, .5, 1.),  \n",
			"								      vec4( .25,  .25, .5, 1.)); \n",
			"\n",
			"    gl_Position = vertices[gl_VertexID]; \n",
			"}\n",
			"\n",
			"\n",
			"\n",
	};
	
	private String fragment_shader[] = {
			"#version 450 core \n",
			"\n",
			"out vec4 color; \n",
			"\n",
			"void main(void) \n",
			"{ \n",
			"    color = vec4(0.0, 0.8, 1.0, 1.0); \n",
			"} \n",
			"\n",
			"\n",
			"\n",
			"\n",
	};
	
	private Shader shader = new Shader();
	
	private String arrayToString(Object[] a) {
		if(a == null)
			return "null";
		
		StringBuilder builder = new StringBuilder();
		for(Object s : a)
			builder.append(String.valueOf(s));
		
		System.out.println("--------------------------------------");
		System.out.println(builder.toString());
		System.out.println("--------------------------------------");
		
		return builder.toString();
	}

	public void init() {
		// Setup an error callback. The default implementation
		// will print the error message in System.err.
		GLFWErrorCallback.createPrint(System.err).set();
		
		if(!glfwInit())
			throw new IllegalStateException("Unable to initialize GLFW");
		
		// Configure our window
		glfwDefaultWindowHints();
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
		glfwWindowHint(GLFW_FOCUSED, GL_TRUE);
		glfwWindowHint(GLFW_SAMPLES , 4);
		
		this.window = glfwCreateWindow(WIDTH, HEIGHT, "Game Test", NULL, NULL);
		
		glfwGetFramebufferSize(this.window, this.screenWidth, this.screenHeight);
		
		if(this.window == NULL) {
			System.err.println("Failed to create GLFW window: " + this.window);
			glfwTerminate(); // clean up GLFW
			throw new RuntimeException("Failed to create GLFW window!");
		}
		
		// Get the resolution of the primary monitor
		GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
		// Center our window
		glfwSetWindowPos(this.window, 
				(vidmode.width() - WIDTH) / 2, (vidmode.height() - HEIGHT) / 2);
		
		glfwMakeContextCurrent(this.window);
		// Enable v-sync
		glfwSwapInterval(1);
		
		// Make the window visible
		glfwShowWindow(this.window);
	}
	
	private void loop() {
		// This line is critical for LWJGL's interoperation with GLFW's
		// OpenGL context, or any context that is managed externally.
		// LWJGL detects the context that is current in the current thread,
		// creates the GLCapabilities instance and makes the OpenGL
		// bindings available for use.
		GL.createCapabilities();
		
		glViewport(0, 0, this.screenWidth.get(), this.screenHeight.get());
		
		double previos = glfwGetTime() * 1000000000;
		final double ns = 1000000000.0 /60;
		double delta = 0.0d;
		
		long timer = System.currentTimeMillis();
		int updates = 0;
		
		shader.compile(arrayToString(vertex_shader), arrayToString(fragment_shader), null);
		
		while(!glfwWindowShouldClose(this.window)) {
			double current = glfwGetTime() * 1000000000;
			double elapsed = current - previos;
			previos = current;
			delta += elapsed;
			
			// Poll for window events. The key callback above will only be
			// invoked during this call.
			glfwPollEvents(); 
			
			while(delta >= ns) {
				update();
				delta -= ns;
				updates++;
			}
			
			if(System.currentTimeMillis() - timer > 1000) {
				timer += 1000;
				System.out.println(updates + " ups");
				updates = 0;
			}
			render(delta / ns);
		}
	}
	
	private void render(double delta) {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
		
		shader.use();
		glDrawArrays(GL_TRIANGLES, 0, 3);
		
			ErrorHandler.glCheckError(this.getClass().getName(), 180);
		
		glfwSwapBuffers(this.window); // swap the color buffers
	}

	private void update() {
		
	}

	public static void main(String[] args) {
		new ProjectZTest();
	}
}


So I am totally lost why the code works in the example code, in my first code gives me an error and in the second code gives me also an error....
And I couldn't track the error from code one more down...... I was also not able to track the error down in the second code....

And as I think anyone can see, in for example the last code I'm just using two OpenGL functions in the code besides the normal functions every render code got. It's just the glUseProgram which is called with shader.use() and then the glDrawArrays().
I'm really starting to think about going back to C++ (even when I'm with C++ a beginner) and stop using LWJGL 3, because I know that in my C++ code the triangle is working with the same shader file and the same glDrawArrays method.

Kai

QuoteAnd I couldn't track the error from code one more down...... I was also not able to track the error down in the second code....
Did you actually try to really track the error down? That means, not just by hard looking at the code, but by actually using step-by-step debugging with synchronous OpenGL Debug output from the driver (as shown in your posts) or by just inserting a glGetErrors() after each and every OpenGL call, so that you actually know where the error occurs?

Anyway, after looking at your code, the source of the INVALID_OPERATION is the glDrawArrays() and the reason is that this method is called without having a Vertex Array Object bound. This is _not_ allowed in OpenGL 4.5 core profile. See PDF page 370 (document page 349) of https://www.opengl.org/registry/doc/glspec45.core.pdf, the last entry in the "Errors" section.
You _must_ use a Vertex Array Object via glGenVertexArrays()/glBindVertexArrays(), even when you don't have a vertex source/buffer.

ShadowDragon

Quote from: Kai on October 30, 2016, 01:13:12
QuoteAnd I couldn't track the error from code one more down...... I was also not able to track the error down in the second code....
Did you actually try to really track the error down? That means, not just by hard looking at the code, but by actually using step-by-step debugging with synchronous OpenGL Debug output from the driver (as shown in your posts) or by just inserting a glGetErrors() after each and every OpenGL call, so that you actually know where the error occurs?

Anyway, after looking at your code, the source of the INVALID_OPERATION is the glDrawArrays() and the reason is that this method is called without having a Vertex Array Object bound. This is _not_ allowed in OpenGL 4.5 core profile. See PDF page 370 (document page 349) of https://www.opengl.org/registry/doc/glspec45.core.pdf, the last entry in the "Errors" section.
You _must_ use a Vertex Array Object via glGenVertexArrays()/glBindVertexArrays(), even when you don't have a vertex source/buffer.
Well, I tracked it down with the step-by-step debugger of eclipse and the error output stuff I implemented to be able to get more information out of the error.
And thx for the answer. That fixed the problem and now I remember that I read about it some time ago.

Also would be nice when you or someone could provide me a guide how to debug efficient OpenGL programs, cause I'm new to OpenGL and still learning.