Hello all,
I recently started learning OpenGL and I'm having a problem when I want to toggle fullscreen on my sf::Window. I'm following the tutorials from open.gl (http://open.gl) and everything has been going smoothly but today I ran into this issue and haven't been able to solve it.
Here is the offending code:
#define GLEW_STATIC
#include <iostream>
#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "Render/RenderUtils.h"
#include "Log.h"
using namespace moony;
int main()
{
sf::VideoMode videoMode = sf::VideoMode(800, 600, 24);
sf::ContextSettings contextSettings = sf::ContextSettings(24, 8, 2);
sf::Window window(videoMode, "SFML OpenGL", sf::Style::Close, contextSettings);
sf::Clock clock;
bool isRunning = true;
bool isFullscreen = false;
// Initialize GLEW
glewExperimental = GL_TRUE;
glewInit();
// Create the VertexArrayObject
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Create the VertexBufferObject
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
// Define a Polygon pos3 col3 tex2
float vertices[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-Left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-Right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-Right
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-Left
};
// Bind VertexBufferObject and send Polygon data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint elementBufferObject;
glGenBuffers(1, &elementBufferObject);
GLuint elements[] =
{
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint shaderProgram = loadShaderProgram("./shaders/shader.vert", "./shaders/shader.frag");
if(!shaderProgram)
return -1;
GLint attribPosition = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(attribPosition);
glVertexAttribPointer(attribPosition, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
GLint attribColor = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(attribColor);
glVertexAttribPointer(attribColor, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
GLint attribTexcoord = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(attribTexcoord);
glVertexAttribPointer(attribTexcoord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
GLint uniformTime = glGetUniformLocation(shaderProgram, "time");
GLuint textureObjects;
glGenTextures(1, &textureObjects);
glBindTexture(GL_TEXTURE_2D, textureObjects);
sf::Image image_a;
if(!image_a.loadFromFile("./textures/sample.png"))
return -1;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_a.getSize().x, image_a.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_a.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUniform1i(glGetUniformLocation(shaderProgram, "texture_a"), 0);
while(isRunning)
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed : isRunning = false; break;
default: break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::F))
{
isFullscreen = !isFullscreen;
if(isFullscreen)
window.create(sf::VideoMode::getFullscreenModes()[0], "", sf::Style::Fullscreen, contextSettings);
else
window.create(videoMode, "SFML OpenGL", sf::Style::Close, contextSettings);
}
window.setActive(true);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniform1f(uniformTime, clock.getElapsedTime().asSeconds());
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Comment this and all goes well.
window.display();
}
glDeleteProgram(shaderProgram);
glDeleteBuffers(1, &elementBufferObject);
glDeleteBuffers(1, &vertexBufferObject);
glDeleteVertexArrays(1, &vertexArrayObject);
window.close();
return 0;
}
The commented line is the problem. When I run it and get to glDrawElements(...); I get a SIGSEGV but when I comment it out no problems toggling fullscreen. I'm new to OpenGL so if I've missed something obvious be patient with me. Thanks in advance.
Someone correct me if I am wrong, but when you recreate the window the context is destroyed/recreated and all your own GL objects are invalidated.
I believe you are right. This code works because I basically put the GPU in the state it was after recreating the window.
#define GLEW_STATIC
#include <iostream>
#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "Render/RenderUtils.h"
#include "Log.h"
using namespace moony;
void remakeContext()
{
// Create the VertexArrayObject
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Create the VertexBufferObject
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
// Define a Polygon pos3 col3 tex2
float vertices[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-Left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-Right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-Right
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-Left
};
// Bind VertexBufferObject and send Polygon data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint elementBufferObject;
glGenBuffers(1, &elementBufferObject);
GLuint elements[] =
{
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint shaderProgram = loadShaderProgram("./shaders/shader.vert", "./shaders/shader.frag");
if(!shaderProgram)
return;
GLint attribPosition = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(attribPosition);
glVertexAttribPointer(attribPosition, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
GLint attribColor = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(attribColor);
glVertexAttribPointer(attribColor, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
GLint attribTexcoord = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(attribTexcoord);
glVertexAttribPointer(attribTexcoord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
GLint uniformTime = glGetUniformLocation(shaderProgram, "time");
GLuint textureObjects;
glGenTextures(1, &textureObjects);
glBindTexture(GL_TEXTURE_2D, textureObjects);
sf::Image image_a;
if(!image_a.loadFromFile("./textures/sample.png"))
return;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_a.getSize().x, image_a.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_a.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUniform1i(glGetUniformLocation(shaderProgram, "texture_a"), 0);
}
int main()
{
sf::VideoMode videoMode = sf::VideoMode(800, 600, 24);
sf::ContextSettings contextSettings = sf::ContextSettings(24, 8, 2);
sf::Window window(videoMode, "SFML OpenGL", sf::Style::Close, contextSettings);
sf::Clock clock;
bool isRunning = true;
bool isFullscreen = false;
// Initialize GLEW
glewExperimental = GL_TRUE;
glewInit();
// Create the VertexArrayObject
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Create the VertexBufferObject
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
// Define a Polygon pos3 col3 tex2
float vertices[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-Left
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-Right
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-Right
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-Left
};
// Bind VertexBufferObject and send Polygon data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint elementBufferObject;
glGenBuffers(1, &elementBufferObject);
GLuint elements[] =
{
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint shaderProgram = loadShaderProgram("./shaders/shader.vert", "./shaders/shader.frag");
if(!shaderProgram)
return -1;
GLint attribPosition = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(attribPosition);
glVertexAttribPointer(attribPosition, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
GLint attribColor = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(attribColor);
glVertexAttribPointer(attribColor, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
GLint attribTexcoord = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(attribTexcoord);
glVertexAttribPointer(attribTexcoord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));
GLint uniformTime = glGetUniformLocation(shaderProgram, "time");
GLuint textureObjects;
glGenTextures(1, &textureObjects);
glBindTexture(GL_TEXTURE_2D, textureObjects);
sf::Image image_a;
if(!image_a.loadFromFile("./textures/sample.png"))
return -1;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_a.getSize().x, image_a.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_a.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUniform1i(glGetUniformLocation(shaderProgram, "texture_a"), 0);
while(isRunning)
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed : isRunning = false; break;
default: break;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::F))
{
isFullscreen = !isFullscreen;
if(isFullscreen)
window.create(sf::VideoMode::getFullscreenModes()[0], "", sf::Style::Fullscreen, contextSettings);
else
window.create(videoMode, "SFML OpenGL", sf::Style::Close, contextSettings);
remakeContext();
}
window.setActive(true);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniform1f(uniformTime, clock.getElapsedTime().asSeconds());
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Comment this and all goes well.
window.display();
}
glDeleteProgram(shaderProgram);
glDeleteBuffers(1, &elementBufferObject);
glDeleteBuffers(1, &vertexBufferObject);
glDeleteVertexArrays(1, &vertexArrayObject);
window.close();
return 0;
}
No more crashing and everything works. I'm sure there is some memory leak problem in here and I really wish this wasn't the solution. It has to be more intuitive than this. Again, OpenGL noob so I'm probably very wrong.
Okay so I solved the crashing, confirmed on some Windows 7 and XP virtual machines and actual hardware. I cut out VAOs all together because I want to target OpenGL 2.1 hardware and the 2.1 spec has all the features I need for this game I want to make. Now I have another issue and that is that on a physical Windows XP install, nothing gets drawn when in fullscreen mode, I just get a black screen. When switching out back into windowed mode drawing resumes as expected. Here is a small code sample that reproduces the issue for me.
#define SFML_STATIC
#include <iostream>
#include <glad/glad.h>
#include <SFML/Window.hpp>
int main(void)
{
sf::VideoMode videoModeWindowed(640, 480);
sf::VideoMode videoModeFullscreen = sf::VideoMode::getFullscreenModes()[0];
sf::ContextSettings contextSettings(24, 8, 0, 2, 1);
sf::Window window(videoModeFullscreen, "SFML OpenGL", sf::Style::Fullscreen, contextSettings);
if(!gladLoadGL())
return -1;
GLfloat clearColor[] = {1.0f, 1.0f, 0.0f, 1.0f};
bool running = true;
bool fullscreen = true;
int delay = 0;
while(running)
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed: running = false; break;
default: break;
}
}
// update
if(window.hasFocus())
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
running = false;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::F) && !delay)
{
fullscreen = !fullscreen;
if(fullscreen)
window.create(videoModeFullscreen, "SFML OpenGL", sf::Style::Fullscreen, contextSettings);
else
window.create(videoModeWindowed, "SFML OpenGL", sf::Style::Close, contextSettings);
delay = 500;
}
if(delay)
delay--;
}
if(fullscreen)
{
clearColor[1] = 0.0f;
clearColor[2] = 1.0f;
}
else
{
clearColor[1] = 1.0f;
clearColor[2] = 0.0f;
}
// render
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
window.display();
}
window.close();
return 0;
}
I tested on Windows 8 hardware and on multiple Windows 7 hardware (not my PC) and no problems at all. When you are in windowed mode you should see a yellow screen and when in fullscreen mode you should see a magenta screen.
Here are the specs of the XP machine that is not complying:
Windows XP Home 32 bit
CPU AMD Sempron 140
GPU Nvidia GeForce 6150SE nForce 430 with latest driver (307.83)
Monitor resolution 1360x768