LWJGL 3 ups & fps counter goes crazy

When the window is moved or resized the fps counter and ups counter goes crazy.

	public static void run() {
		long lastTime = System.nanoTime();
		long now;
		long timer = System.currentTimeMillis();
		double delta = 0;
		int frames = 0;
		int updates = 0;
		while (running) {
			if (Window.shouldClose() == true) {
				stop();
			}
			now = System.nanoTime();
			delta += (now - lastTime) / Final.NS;
			lastTime = now;
			while (delta >= 1) {
				update();
				updates++;
				delta--;
			}
			render();
			frames++;
			if (System.currentTimeMillis() - timer > 1000) {
				timer += 1000;
				System.out.println(updates + " ups, " + frames + " fps");
				updates = 0;
				frames = 0;
			}
		}
		dispose();
	}

This is the game loop it is suppose to run the update method 60 times a second, and the render method has no limit per second.
The counters work fine until you move or resize the window.

package engine;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWCursorPosCallback;
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWMouseButtonCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.system.MemoryUtil;

import engine.input.Cursor;
import engine.input.Keyboard;
import engine.input.Mouse;
import engine.util.Final;

public class Window {

	private static String title = Final.TITLE;
	private static long id;
	private static int width = Final.WINDOW_WIDTH;
	private static int height = Final.WINDOW_HEIGHT;
	private static boolean fullscreen = Final.WINDOW_FULLSCREEN;
	private static boolean vsync = Final.WINDOW_VSYNC;
	private static boolean visible = Final.WINDOW_VISIBILITY;
	private static boolean resizable = Final.WINDOW_RESIZABLE;

	private static final GLFWFramebufferSizeCallback FRAMEBUFFER_SIZE_CALLBACK = new GLFWFramebufferSizeCallback(){
		@Override
		public void invoke(long window, int width, int height) {
			GL11.glViewport(0, 0, width, height);
		}
	};
	private static final GLFWWindowSizeCallback WINDOW_SIZE_CALLBACK = new GLFWWindowSizeCallback(){
		@Override
		public void invoke(long window, int width, int height) {
			Window.width = width;
			Window.height = height;
		}
	};
	private static final GLFWKeyCallback KEY_CALLBACK = new Keyboard();;
	private static final GLFWMouseButtonCallback MOUSE_BUTTON_CALLBACK = new Mouse();
	private static final GLFWCursorPosCallback CURSOR_POS_CALLBACK = new Cursor();

	public Window() {
		if (GLFW.glfwInit() != GLFW.GLFW_TRUE) {
			throw new IllegalStateException("Unable to initialize GLFW");
		}
		GLFW.glfwDefaultWindowHints();
		GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
		GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
		GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
		GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
		GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, visible ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
		GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, resizable ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
		id = GLFW.glfwCreateWindow(width, height, title, fullscreen ? GLFW.glfwGetPrimaryMonitor() : MemoryUtil.NULL, MemoryUtil.NULL);
		if (id == MemoryUtil.NULL) {
			GLFW.glfwTerminate();
			throw new RuntimeException("Failed to create the GLFW window");
		}
		GLFWVidMode vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
		GLFW.glfwSetWindowPos(id, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
		GLFW.glfwSwapInterval(vsync ? 1 : 0);
		GLFW.glfwMakeContextCurrent(id);
		FRAMEBUFFER_SIZE_CALLBACK.set(id);
		WINDOW_SIZE_CALLBACK.set(id);
		KEY_CALLBACK.set(id);
		MOUSE_BUTTON_CALLBACK.set(id);
		CURSOR_POS_CALLBACK.set(id);
		GL.createCapabilities();
	}

	public static void update() {
		GLFW.glfwSwapBuffers(id);
		GLFW.glfwPollEvents();
	}

	public static void dispose() {
		GLFW.glfwDestroyWindow(id);
		FRAMEBUFFER_SIZE_CALLBACK.release();
		WINDOW_SIZE_CALLBACK.release();
		KEY_CALLBACK.release();
		MOUSE_BUTTON_CALLBACK.release();
		CURSOR_POS_CALLBACK.release();
		GLFW.glfwTerminate();
	}

	public static void setWidth(int width) {
		Window.width = width;
	}

	public static int getWidth() {
		return width;
	}

	public static void setHeight(int height) {
		Window.height = height;
	}

	public static int getHeight() {
		return height;
	}

	public static void setTitle(String title) {
		Window.title = title;
	}

	public static void setVsync(boolean vsync) {
		Window.vsync = vsync;
		GLFW.glfwSwapInterval(vsync ? 1 : 0);
	}

	public static void setVisiblity(boolean visible) {
		Window.visible = visible;
		if(visible){
			GLFW.glfwShowWindow(id);
		}else{
			GLFW.glfwHideWindow(id);
		}
	}

	public static long getID() {
		return id;
	}

	public static boolean shouldClose() {
		return GLFW.glfwWindowShouldClose(id) == GLFW.GLFW_TRUE;
	}
}

This is the window class I am using. The only thing I can think of is that LWJGL’s callbacks are messing it up. But I do not know why they would.

When you drag or resize the window the program pauses. So when you stop dragging/resizing the elapsed time is greater.

Try capping the delta.

Wouldn’t it just mess up for one iteration, and then start working right again? The counter does not work after the the resize or move.

I do this in my loop instead:

That’s the problem with saying, “Does not work”/“Goes Crazy”. It doesn’t mean anything to us. What do you mean doesn’t work? It stops updating entirely, seems to be fast, seems to be slow?

It runs at 60 ups, 45157442 fps until I move it and then it goes to 63 ups, 3 fps. So the ups get higher and the fps get lower.

Well that’s expected. If you don’t want this to happen when you drag/resize then you have to cap your delta.

What is this loop technique called?

its a standard game loop

while(running){
update();
render();
}
dispose();

Final.NS = 1000000000.0 / UPS_CAP;
UPS_CAP = 60;

Your updates are independent of the frames the way you have it. There should be 1 update in a standard game-loop.

try something like this:


public static void run() {
      long lastTime = System.nanoTime();
      long now;
      long timer = System.currentTimeMillis();
      double delta = 0;
      int frames = 0;
      while (running) {
         if (Window.shouldClose() == true) {
            stop();
         }

         now = System.nanoTime();
         delta = (now - lastTime) / (1000000000f / targetFps);
         lastTime = now;

         update(delta); //interpolate using the delta
         render();

         frames++;
         if (System.currentTimeMillis() - timer > 1000) {
            timer += 1000;
            System.out.println(frames + " fps");
            frames = 0;
         }
      }
      dispose();
   }

You can keep rendering separate from window message processing (i.e. moving/resizing, etc.) by using the main thread to do only glfwWaitEvents() and a separate thread for the OpenGL calls and swap buffers.
This way the scene still renders even when you resize/move the window.
But beware that this means multithreading, which can become difficult.

You can see a demo of this in the lwjgl3 GitHub repository and the lwjgl3-demos repository.