Unbound Shader Program Error When Using ImGui
Version
1.87.6
What happened?
I'm encountering an error related to shader program binding while using ImGui with LWJGL and OpenGL. The error message reads:
GL_INVALID_OPERATION error generated. No active program. GL_INVALID_OPERATION error generated. Invalid VAO/VBO/pointer usage. GL_INVALID_OPERATION error generated. Target buffer must be bound.
When running the application with ImGui rendering enabled, the OpenGL shaders seem to be unbound, and the program fails to render properly. The error does not occur when ImGui is disabled.
This code was pretty much taken from the GamesWithGabe lwjgl imgui tutorial linked in the main page. If I am just implementing this incorrectly, please let me know.
Heres the code:
import imgui.ImFontConfig; import imgui.ImGui; import imgui.ImGuiIO; import imgui.flag.ImGuiConfigFlags; import imgui.gl3.ImGuiImplGl3; import imgui.glfw.ImGuiImplGlfw; import imgui.type.ImInt; import org.lwjgl.Version; import org.lwjgl.glfw.Callbacks; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL43; import org.lwjgl.opengl.GLDebugMessageCallback;
import static org.lwjgl.glfw.GLFW.; import static org.lwjgl.opengl.GL11.; import static org.lwjgl.opengl.GL20C.glUseProgram; import static org.lwjgl.opengl.GL30.glBindVertexArray; import static org.lwjgl.system.MemoryUtil.NULL;
public class Window { private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw(); private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
private String glslVersion = null;
private long windowPtr;
private ImGuiLayer imguiLayer;
public Window(ImGuiLayer layer) {
imguiLayer = layer;
}
public void init() {
initWindow();
initImGui();
imGuiGlfw.init(windowPtr, true);
ImGui.getIO().getFonts().getTexDataAsRGBA32(new ImInt(255), new ImInt(255), new ImInt(255));
imGuiGl3.init(glslVersion);
}
public void destroy() {
imGuiGl3.shutdown();
imGuiGlfw.shutdown();
ImGui.destroyContext();
Callbacks.glfwFreeCallbacks(windowPtr);
glfwDestroyWindow(windowPtr);
glfwTerminate();
}
private void initWindow() {
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( !glfwInit() ) {
System.out.println("Unable to initialize GLFW");
System.exit(-1);
}
glslVersion = "#version 460";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
windowPtr = glfwCreateWindow(1920, 1080, "My Window", NULL, NULL);
if (windowPtr == NULL) {
System.out.println("Unable to create window");
System.exit(-1);
}
glfwMakeContextCurrent(windowPtr);
glfwSwapInterval(1);
glfwShowWindow(windowPtr);
GL.createCapabilities();
GL43.glEnable(GL43.GL_DEBUG_OUTPUT);
GL43.glDebugMessageCallback(
GLDebugMessageCallback.create((source, type, id, severity, length, message, userParam) -> {
System.err.println("GL CALLBACK: " + severity + " - " + GLDebugMessageCallback.getMessage(length, message));
}),
0
);
System.out.println("OpenGL version: " + glGetString(GL_VERSION));
}
private void initImGui() {
ImGui.createContext();
ImGuiIO io = ImGui.getIO();
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
// Explicitly build font atlas
io.getFonts().setLocked(false);
final ImFontConfig fontConfig = new ImFontConfig();
fontConfig.setMergeMode(true);
fontConfig.setFontDataOwnedByAtlas(false);
fontConfig.setGlyphRanges(io.getFonts().getGlyphRangesDefault());
io.getFonts().addFontDefault();
io.getFonts().build();
fontConfig.destroy();
// Initialize GLFW and OpenGL backends
imGuiGlfw.init(windowPtr, true);
imGuiGl3.init(glslVersion);
}
public void run() {
while (!glfwWindowShouldClose(windowPtr)) {
glClearColor(0.1f, 0.09f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
imGuiGlfw.newFrame();
ImGui.newFrame();
imguiLayer.imgui(); // Your ImGui content
ImGui.render();
imGuiGl3.renderDrawData(ImGui.getDrawData());
// Optionally reset OpenGL state
glUseProgram(0); // Unbind any program
glBindVertexArray(0); // Unbind VAO
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
ImGui.updatePlatformWindows();
ImGui.renderPlatformWindowsDefault();
GLFW.glfwMakeContextCurrent(backupWindowPtr);
}
GLFW.glfwSwapBuffers(windowPtr);
GLFW.glfwPollEvents();
}
}
Reproduction
Initialize GLFW window and OpenGL context. Initialize ImGui with LWJGL backend (ImGuiImplGlfw, ImGuiImplGl3). Call imGuiGlfw.newFrame() and ImGui.newFrame() in the main render loop. Render ImGui content using ImGui.render() and imGuiGl3.renderDrawData(ImGui.getDrawData()). Observe the OpenGL errors related to unbound shader programs.
Relevant log output
No response
Please try the Application module to check if Dear ImGui does work on your system in general. This will help to understand if there is a problem on the binding side.
The Application module does indeed work.
In that case the problems you've met are rely in a sphere of your local code. I recommend to follow configuration steps from the Application class.
Also, looking through your code I see
// Optionally reset OpenGL state
glUseProgram(0); // Unbind any program
glBindVertexArray(0); // Unbind VAO
This looks very odd to me and may be partly the reason of your errors.
I've just updated to 1.90.0 from 1.86.11, and now I'm getting the same error, whereas I wasn't before. What's funny is that it doesn't actually happen on the first frame rendered; only the second frame.
My code looks like this. Any ideas?
/**
* Draw all open apps to the screen.
* @param client Minecraft client instance.
*/
public static void render(MinecraftClient client) {
RenderSystem.assertOnRenderThread();
boolean isCleanupFrame = apps.isEmpty();
if (client.mouse.isCursorLocked()) {
ImGui.getIO().addConfigFlags(ImGuiConfigFlags.NoMouse);
} else {
ImGui.getIO().removeConfigFlags(ImGuiConfigFlags.NoMouse);
}
forwardInputNextFrame = false;
forwardMouseInputNextFrame = false;
forceMouseUnlock = false;
if (isCleanupFrame && !needsCleanupFrame)
return;
ImGuiUtil.IM_GLFW.newFrame();
ImGui.newFrame();
ImGui.pushFont(Fonts.inter());
for (CraftApp app : apps) {
ImGui.pushID(app.getClass().getCanonicalName().hashCode());
try {
app.render(client);
} catch (Exception e) {
CrashReport crashReport = new CrashReport("Error rendering CraftUI app " + app.getClass().getSimpleName(), e);
throw new CrashException(crashReport);
}
ImGui.popID();
}
ImGui.popFont();
if (isCleanupFrame) {
ImGui.setWindowFocus(null);
ImGui.getIO().setWantCaptureKeyboard(false);
ImGui.getIO().setWantCaptureMouse(false);
}
ImGui.render();
ImGuiUtil.IM_GL3.renderDrawData(ImGui.getDrawData());
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
long backupWindowPtr = glfwGetCurrentContext();
ImGui.updatePlatformWindows();
ImGui.renderPlatformWindowsDefault();
glfwMakeContextCurrent(backupWindowPtr);
}
if (ImGui.getIO().getWantSaveIniSettings() && CraftUI.getConfig().isLayoutPersistent()) {
IniSettingsManager.setImGuiSettings(ImGui.saveIniSettingsToMemory());
IniSettingsManager.saveToDisk();
ImGui.getIO().setWantSaveIniSettings(false);
}
needsCleanupFrame = !isCleanupFrame;
}
The crash happens on IM_GL3.renderDrawData