[Solved] I dont understand this error

Started by Cornix, June 26, 2015, 22:39:11

Previous topic - Next topic

Cornix

Hi guys,
I have spent hours on this, to me it seems like this program is fine, but OpenGL says there is an error.

The problem is with immediate mode glBegin / glEnd rendering. For some odd reason when there is a glBegin followed by a glEnd the program will generate an error.
But if I only use glBegin without glEnd then everything works fine and is rendered. Oo
Shouldnt it be the other way around? I dont understand...

The important things happen inside the "run" method. I commented the line that produces the problem.
The error I get is an illegal_operation error.

import static org.lwjgl.glfw.Callbacks.errorCallbackPrint;
import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.glfw.GLFW.glfwPollEvents;
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
import static org.lwjgl.glfw.GLFW.glfwShowWindow;
import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
import static org.lwjgl.glfw.GLFW.glfwTerminate;
import static org.lwjgl.glfw.GLFW.glfwWindowHint;
import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL11.GL_STENCIL_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_TRUE;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.system.MemoryUtil.NULL;

import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLContext;

public class ErrorMain {
	
	public static void main(String[] args) {
		new ErrorMain();
	}
	
	private	static final String		TITLE		= "Main";
	public	static final int		WIDTH		= 1024;
	public	static final int		HEIGHT		= 768;
	
	private GLFWErrorCallback	errorCallback;
	private long				windowHandle;
	
	private ErrorMain() {
		try {
			initialize();
			run();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			terminate();
		}
	}
	
	private void initialize() {
		errorCallback = errorCallbackPrint(System.err);
		glfwSetErrorCallback(errorCallback);
		
		if (glfwInit() != GL_TRUE) {
			throw new IllegalStateException("glfwInit() != GL_TRUE");
		}
		glfwDefaultWindowHints();
		glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
		glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
		
		windowHandle = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
		if ( windowHandle == NULL ) {
			throw new IllegalStateException("windowHandle == NULL");
		}
		
		glfwMakeContextCurrent(windowHandle);
		glfwSwapInterval(1);
		
		glfwShowWindow(windowHandle);
		GLContext.createFromCurrent();
		
		GL11.glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
	}
	
	private void run() {
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		
		int clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
		while (glfwWindowShouldClose(windowHandle) == GL_FALSE) {
			glClear(clearBits);
			
			GL11.glBegin(GL11.GL_TRIANGLES);
			glError("initialize", "glBegin");
			GL11.glColor4f(1, 0, 0, 1);
			GL11.glVertex2f(0, 0);
			GL11.glVertex2f(0, 32);
			GL11.glVertex2f(32, 32);
			
			// === This line creates the error! ===
			GL11.glEnd();
			// === If I comment glEnd() the program runs fine Oo ===
			glError("initialize", "glEnd");
			
			glfwSwapBuffers(windowHandle);
			
			glfwPollEvents();
		}
	}
	
	private void terminate() {
		try {
			glfwDestroyWindow(windowHandle);
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			glfwTerminate();
			errorCallback.release();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// Just a utility method to throw an exception in case of a glError
	public static void glError(Object cause, String command) {
		int errorCode = GL11.glGetError();
		if (errorCode == GL11.GL_NO_ERROR) {
			return;
		}
		StringBuilder str = new StringBuilder();
		str.append(cause);
		str.append(" caused an error with method ");
		str.append(command);
		str.append(':');
		str.append(' ');
		String msg = str.toString();
		
		switch (errorCode) {
		case GL11.GL_INVALID_VALUE:
			throw new RuntimeException(msg);
		case GL11.GL_INVALID_ENUM:
			throw new RuntimeException(msg);
		case GL11.GL_INVALID_OPERATION:
			throw new RuntimeException(msg);
		case GL11.GL_STACK_OVERFLOW:
			throw new RuntimeException(msg);
		case GL11.GL_STACK_UNDERFLOW:
			throw new RuntimeException(msg);
		case GL11.GL_OUT_OF_MEMORY:
			throw new RuntimeException(msg);
		default:
			throw new RuntimeException(msg + '\n' + "Unknown error.");
		}
	}
	
}

Kai

It is an error to call glGetError within glBegin()/glEnd().
Move the first call to glGetError before glBegin.
Googling this brought this nice thread on www.opengl.org

Cornix

What? Really?
This is incredible. I would have thought you can call glError any time.

Moving the glError before the glBegin does indeed fix the error that glEnd generates. But why does it still work without the glEnd without generating any errors? Is this just weird driver dependent hocus pocus?

Kai

QuoteBut why does it still work without the glEnd without generating any errors? Is this just weird driver dependent hocus pocus?
Hm, don't know about your driver, but with me it does not work if I don't call glEnd().
It creates a weird flickering and the GL matrix stacks also do not seem to get updated.
I tested this with your demo and some programs using immediate mode of mine. All the same there: Flickering with GL matrices not getting updated.

Cornix

Okay, so it is my driver then. Weird.

But thanks, I would have never guessed this.
I wonder why glError is not allowed to be called within a glBegin block. I mean, all those functions can generate an error, why are you not allowed to query it?

quew8

It is indeed one of the most perplexing bugs you can get in legacy OpenGL, where trying to find out what the error is generates it's own error. A truly Microsoft level of confusion there.

As for the no bug without glEnd() conundrum, I think put it down to undefined behaviour in a legacy api. If you look at the specifications, the error would actually be generated on the next call to glBegin() but inbetween that, all sorts of things are likely to be happening under the hood.

But obviously ... legacy api ... shouldn't really be using anyway ...