Trouble driving a 240 Hz monitor through vsync reliably

I’m using OpenGL to display a pattern on a 240 Hz screen with Nvidia GTX 1070 1582 MHz graphics card Windows 10, and I’m encountering some problems with frame dropping/ skipping. To simplify the problem, I created a program that change the background color of the screen between black and white for every frame. The behavior that I observed is this:

  • During the first 11 seconds, 2-4 small glitches (a frame dropped or a frame skipped) will occur
  • At around 30 seconds, a “big glitch” occurs. This is either a white or black flash that span several frames.
  • After that, the black-white-black transitions perfectly every frame (the longest test I’ve run is 5 mins).

I’m not sure why the errors occur in a systematic manner like that. The simple program ensured that graphics rendering time is very fast, and the gpu should be fast enough to copy pixels to the screen.

I tracked the program by using Process Monitor on windows. I noticed that a few seconds before the big glitch occur at the 30 second mark, the program creates 2 new threads. When I track those 2 threads using the thread ID in Process Monitor, it unfortunately doesn’t lead to anywhere. They just got closed when the program exits.

Any ideas on what might be causing this.?

Code of the simple program:

int main(void)
    {
    	// Initialise GLFW
    	if (!glfwInit())
    	{
    		fprintf(stderr, "Failed to initialize GLFW\n");
    		getchar();
    		return -1;
    	}
     
    	glfwWindowHint(GLFW_SAMPLES, 4);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     
    	int count;
     
    	GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor();
    	const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor);
     
    	// Open a window and create its OpenGL context
    	window = glfwCreateWindow(mode->width, mode->height, "Playground", primaryMonitor, NULL);
     
    	if (window == NULL) {
    		fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
    		getchar();
    		glfwTerminate();
    		return -1;
    	}
    	glfwMakeContextCurrent(window);
     
    	// Initialize GLEW
    	glewExperimental = true; // Needed for core profile
    	if (glewInit() != GLEW_OK) {
    		fprintf(stderr, "Failed to initialize GLEW\n");
    		getchar();
    		glfwTerminate();
    		return -1;
    	}
     
    	// Ensure we can capture the escape key being pressed below
    	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
     
    	// Enable VSync
    	glfwSwapInterval(1);
    	float grayValueNormal1 = 0.0f;
    	do {
    		grayValueNormal1 = 1 - grayValueNormal1;
     
    		// Alternate the screen from black to white to black every frame
    		glClear(GL_COLOR_BUFFER_BIT);
    		glClearColor(grayValueNormal1, grayValueNormal1, grayValueNormal1, 0.0f);
    		glfwSwapBuffers(window);
     
    		glfwPollEvents();
     
    	} // Check if the ESC key was pressed or the window was closed
    	while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
    		glfwWindowShouldClose(window) == 0);
     
    	// Close OpenGL window and terminate GLFW
    	glfwTerminate();
     
    	return 0;
    }

Reply With Quote Reply With Quote   Multi-Quote This Message

So I investigated further and found out that ntdll.dll is the owner of those 2 threads. This dll owns 3 threads during initialization, then roughly 30 seconds in got closed, then reappears in 2 new threads. The timing of the opening of the 2 new threads are very close to the big frame drop that occurred.

So I changed the driver settings of the Power Management Mode from “Optimal Power” to “Prefer Maximum Performance” and I got consistent behavior now (In my test program to color the screen background from black-white-black for every frame, the transition happens reliably without any glitch).

I’d have to do more tests before jumping to a conclusion, but it looks good for now. No idea why this solved it though.