glfwCreateWindow hangs when creating fullscreen window on secondary monitor


#1

I’m trying to create a full screen render window on a secondary monitor. The following is a relatively simple example that exhibits the error. When I set monitor_num to anything but 0 (i.e. my main/primary display) my code hangs at the glfwCreateWindow line. What am I doing wrong?

I’m operating on a Windows 10, 64-bit system with an Nvidia GPU and Visual Studio 2013.

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <stdlib.h>
#include <stdio.h>

GLuint			programID;
GLuint			vao;
GLuint			vertexbuffer;

#define monitor_num 1


static void error_callback(int error, const char* description)
{
	fputs(description, stderr);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}
void setup_shaders(void);
int main(void)
{
	GLFWwindow* window;
	glfwSetErrorCallback(error_callback);
	if (!glfwInit())
		exit(EXIT_FAILURE);

	int number_of_monitors;
	GLFWmonitor** monitors = glfwGetMonitors(&number_of_monitors);
	const GLFWvidmode * current_mode = glfwGetVideoMode(monitors[monitor_num]);

	glfwWindowHint(GLFW_MAXIMIZED, GL_TRUE);
	glfwWindowHint(GLFW_AUTO_ICONIFY, GL_FALSE);
	window = glfwCreateWindow(current_mode->width, current_mode->height, "Simple example", monitors[monitor_num], NULL);
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glfwMakeContextCurrent(window);
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		return false;
	}
	glfwSetKeyCallback(window, key_callback);

	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);
	setup_shaders();
	static const GLfloat g_vertex_buffer_data[] = 
	{
		-0.6f, -0.4f, 0.f, 
		 0.6f, -0.4f, 0.f,
		 0.f,   0.6f, 0.f,
	};

	glGenBuffers(1, &vertexbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);
	glUseProgram(0);

	while (!glfwWindowShouldClose(window))
	{
		glUseProgram(programID);
		glBindVertexArray(vao);
		glEnableVertexAttribArray(0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
		glDrawArrays(GL_TRIANGLES, 0, 3); 
		glDisableVertexAttribArray(0);
		glBindVertexArray(0);
		glUseProgram(0);
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}


void setup_shaders(void)
{
	static const char * gl_vertex_shader_source_code[] =
	{
		"#version 330 core												\n"
		"																\n"
		"layout(location = 0) in vec3 vertexPosition_modelspace;		\n"
		"																\n"
		"void main(){													\n"
		"																\n"
		"	gl_Position = vec4(vertexPosition_modelspace, 1);			\n"
		"}																\n"
	};

	static const GLchar * gl_fragment_shader_source_code[] =
	{
		"#version 330 core												\n"
		"																\n"
		"out vec3 color;												\n" 
		"																\n"
		"void main()													\n"
		"{																\n"
		"	color = vec3(0.5, 1.0, 0.8);								\n" 
		"}																\n"
	};

	GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex_shader, 1, gl_vertex_shader_source_code, NULL);
	glCompileShader(vertex_shader);


	GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment_shader, 1, gl_fragment_shader_source_code, NULL);
	glCompileShader(fragment_shader);

	programID = glCreateProgram();
	glAttachShader(programID, vertex_shader);
	glAttachShader(programID, fragment_shader);
	glLinkProgram(programID);

	glDeleteShader(vertex_shader);
	glDeleteShader(fragment_shader);
}

#2

Have you checked that number_of_monitors > monitor_num?


#3

I have three monitors connected (& number_of_monitors does report back as 3). So, in this case, when monitor_num == 0, it works. But when monitor_num == 1 or 2, it hangs.


#4

Are you able to debug the code and find out where it hangs?

Additionally have you tested starting the app windowed, then switching fullscreen to that monitor?


#5

Yes - I was debugging the code all along and it was hanging at the glfwCreateWindow command.

However, as you suggested, if I create a windowed version first and then call glfwSetWindowMonitor, I am able to switch to fullscreen mode just fine. That appears to have solved the problem.

Thanks.


#6

There could be a bug here which may need reporting but it might be difficult for the maintainers to investigate if they can’t reproduce.

If you have a little time to dig further, you could try this with the latest code on github and if the problem persists attempt to find out where in the glfw code it is hanging. To make sure the debugger itself isn’t causing the hang (debugging fullscreen apps can cause issues), you might need to start with the debugger detached and then attach and pause when the problem occurs.


#7

I am running GLFW v3.2.1 which, on github, is reported as the latest stable release.

Unfortunately, I don’t have a lot of time to debug the latest GLFW source. That’s why I tried to create the example code above which represents the simplest set of commands using modern OpenGL that is demonstrating this error. I would be curious if anyone else can run this code and show similar behavior. (I have been able to get the same failure on two different systems - one running Visual Studio 2015 and one running Visual Studio 2013).

I wish I had time to debug the GLFW source (but I’m not even sure how to detach and reattach the debugger mid-program, as you suggest!). That being said, I just downloaded the latest GLFW source (version 3.3). Generated a visual studio project w/ CMake and implemented the above code. Here’s my trace of where the bug is occurring:

 glfwCreateWindow
      ===> __glfwRefreshContextAttribs(&ctxconfig) (@ line 212 of window.c)
               ===> window->context.swapBuffers(window); (@ line 541 of context.c)
                         ===> SwapBuffers(window->context.wgl.dc); (@ line 266 of wgl_context.c)

I can’t proceed any deeper than this function. The code just hangs at the above line.

As an aside, I am seeing another odd artifact when using the glfwSetWindowMonitor command as described above. The window will open up full-screen in the desired monitor - but the viewport coordinates are scaled incorrectly. For example, if I create a triangle whose vertices should touch two corners and the top center of the screen, it will display correctly if I go full-screen on my main display - but if I transfer to either my secondary monitors, the triangle will be mis-scaled (hanging off the side of the screen.) I’m going to try to debug that on my own. I will probably start a different question thread on that issue if I can’t figure it out.


#8

Quick update: My last observation of said ‘odd artifact’ is corrected with a call to:
glViewport(0, 0, current_mode->width, current_mode->height);

When you switch over to the secondary monitor, the original (main) display’s viewport is still locked in.


#9

GLFW doesn’t have a test for starting fullscreen on different monitors, but I recently added the ability to do so on my own project Avoyd in version 0.1.0.152 which you can download for free to see if this is a GLFW issue or something in your code.

If you select Resize->Fullscreen Options you can choose which monitor and resolution to go fullscreen on. If you then close Avoyd when in fullscreen and restart it should restart on the same monitor, if not there’s a problem and I’ll try to get you some test code with extra debug information.