SFML community forums

Help => General => Topic started by: homar on January 07, 2014, 07:32:22 pm

Title: Loading thread using a second OpenGL context
Post by: homar on January 07, 2014, 07:32:22 pm
My plan was to create a loading thread inside of which I load resources such as 3D models, shaders, textures, etc. On the main thread I perform all the game logic and rendering. Then, on my loading thread, I create a sf::Context which is used only for loading.

This is working for loading shaders. However, xserver crashes when attempting to load models. I have narrowed the crash down to the glBufferData() call.

Is it possible call glBufferData() from a second thread using a second OpenGL context? If not, why is it possible to load shaders in the second context?
Title: Re: Loading thread using a second OpenGL context
Post by: amir ramezani on January 07, 2014, 07:37:09 pm
firstly, create your context and initialize it with a function
now initialize 2 threads, one for a function that initialize's the context, another for process the context
now, when you want to process it, you just call the lunch method
but, you have to give the functions in the thread constructor
Title: Re: Loading thread using a second OpenGL context
Post by: homar on January 08, 2014, 12:16:45 am
This is essentially what I am doing.
Please find below a small example program that reproduces the crash:

#include <iostream>
#include <thread>

#include <GL/glew.h>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics.hpp>
#include <X11/Xlib.h>

class ResourceLoader
{
public:
        void Run()
        {
                sf::Context loadingContext;
                loadingContext.setActive(true);

                // Some test data.
                float* testData = new float[3000];
                for (unsigned int i = 0; i < 3000; ++i)
                {
                        testData[i] = 0.0f;
                }

                // Create lots of VBOs containing our
                // test data.
                for (unsigned int i = 0; i < 1000; ++i)
                {
                        // Create VBO.
                        GLuint testVBO = 0;
                        glGenBuffers(1, &testVBO);
                        std::cout << "Buffer ID: " << testVBO << std::endl;

                        // Bind VBO.
                        glBindBuffer(GL_ARRAY_BUFFER, testVBO);

                        // Crashes on this call!
                        glBufferData(
                                GL_ARRAY_BUFFER,
                                sizeof(float) * 3000,
                                &testData[0],
                                GL_STATIC_DRAW
                        );

                        // Unbind VBO.
                        glBindBuffer(GL_ARRAY_BUFFER, 0);

                        // Sleep for a bit.
                        std::this_thread::sleep_for(std::chrono::milliseconds(10));
                }

                delete[] testData;
        }
};

int main()
{
        XInitThreads();

        // Create the main window.
        sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window", sf::Style::Default, sf::ContextSettings(32));
        window.setVerticalSyncEnabled(true);

        // Make it the active window for OpenGL calls.
        window.setActive();

        // Configure the OpenGL viewport to be the same size as the window.
        glViewport(0, 0, window.getSize().x, window.getSize().y);

        // Initialize GLEW.
        glewExperimental = GL_TRUE; // OSX fix.
        if (glewInit() != GLEW_OK)
        {
                window.close();
                exit(1); // failure
        }

        // Enable Z-buffer reading and writing.
        glEnable(GL_DEPTH_TEST);
        glDepthMask(GL_TRUE);

        // Create the resource loader.
        ResourceLoader loader;

        // Run the resource loader in a separate thread.
        std::thread loaderThread(&ResourceLoader::Run, &loader);

        // Detach the loading thread, allowing it to run
        // in the background.
        loaderThread.detach();

        // Game loop.
        while (window.isOpen())
        {
                // Event loop.
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                }

                // Clear scren.
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // Switch to SFML's OpenGL state.
                window.pushGLStates();
                {
                        // Perform SFML drawing here...
                        sf::RectangleShape rect(sf::Vector2f(100.0f, 100.0f));
                        rect.setPosition(100.0f, 100.0f);
                        rect.setFillColor(sf::Color(255, 255, 255));
                        window.draw(rect);
                }
                // Switch back to our game rendering OpenGL state.
                window.popGLStates();

                // Perform OpenGL drawing here...


                // Display the rendered frame.
                window.display();
        }

        return 0;
}