SFML community forums

Help => Window => Topic started by: Ricky on November 01, 2015, 07:51:02 am

Title: Fullscreen when using OpenGL
Post by: Ricky on November 01, 2015, 07:51:02 am
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.
Title: Re: Fullscreen when using OpenGL
Post by: zsbzsb on November 01, 2015, 08:08:19 am
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.
Title: Re: Fullscreen when using OpenGL
Post by: Ricky on November 01, 2015, 08:22:58 am
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.
Title: Re: Fullscreen when using OpenGL
Post by: Laurent on November 01, 2015, 11:14:29 am
SFML internally creates hidden OpenGL contexts, and all of them share their resources. This means that even if you recreate your window, the resources are not lost. The only exception being OpenGL objects that cannot be shared among contexts: VAO. So technically you would only have to recreate your VAO to avoid the problem.
Title: Re: Fullscreen when using OpenGL
Post by: mkalex777 on November 01, 2015, 01:35:28 pm
SFML internally creates hidden OpenGL contexts, and all of them share their resources. This means that even if you recreate your window, the resources are not lost. The only exception being OpenGL objects that cannot be shared among contexts: VAO. So technically you would only have to recreate your VAO to avoid the problem.

Very interesting comment. What is VAO? Vertex arrays?
Title: Re: Fullscreen when using OpenGL
Post by: Nexus on November 01, 2015, 02:08:29 pm
Vertex Array Object (https://www.opengl.org/wiki/Vertex_Specification#Vertex_Array_Object) (not the same as sf::VertexArray)
Title: Re: Fullscreen when using OpenGL
Post by: Ricky on November 05, 2015, 04:36:08 am
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
Title: Re: Fullscreen when using OpenGL
Post by: Ricky on November 10, 2015, 07:42:13 am
I fixed it. There was actually a problem with the Windows XP installation and when I reinstalled Windows XP it worked. Cheers!  ;D