c++openglglfwabstractionglew

How to correctly manage renderer initialization in the window constructor?


As an exercise, I'm writing a simple wrapper in C++ around GLFW and OpenGL. I have two classes: Window and Renderer, where Window owns an instance of Renderer.

The Window class sets up the GLFW context in its constructor, runs the main loop, and uses its Renderer member to handle drawing. The Renderer class sets up the buffers in its constructor and handles OpenGL function calls.

The issue I'm facing is that OpenGL requires a valid context for any function calls. If I initialize Renderer before the Window constructor is called, the Renderer constructor will run before the GLFW context is created.

To avoid this, I store a unique_ptr to Renderer in the Window class and instantiate it using std::make_unique<Renderer> inside the Window constructor. Then, in the Window destructor, I call std::unique_ptr::reset() before destroying the GLFW context to ensure that OpenGL calls can still be made to release resources while the context is valid.

class Window
{
   public:
       Window()
       {
           // Initializing GLFW and creating an OpenGL context
           // ...
           m_renderer = std::make_unique<Renderer>();
       }
       ~Window()
       {
           m_renderer.reset();
           glfwTerminate();
       }
       int run()
       {
           while(...)
           {
               m_renderer->draw();
               // ...
           }
           return 0;
       }
   private:
       std::unique_ptr<Renderer> m_renderer; 
       // ...
}

class Renderer
{
    public:
        Renderer() { /* Set buffers */ }
        ~Renderer() { /* Free buffers */ }
        draw() { glDrawElements(...); /* ... */ }
    private:
        // ...
}

int main()
{
     Window window();
     return window->run();
}
        

I understand that the Renderer object should already be initialized when calling the Window constructor, which is not the case here. I feel I might have inverted the dependency between Renderer and Window, or my overall architecture might be wrong. I would rather rely on the constructor and destructor being called at the right moment based on the scope than triggering it manually.

What would be a better solution?


Solution

  • I suggest that you create a separate class, call it GLFWInit that does the GLFW initialization and calls glfwTerminate() in its destructor. Then you have two options:

    1. Embed an object of type GLFWInit in your Window class. Place the member early, but at the least before the m_renderer member.

    2. Derive your Window class from GLFWInit.

    Both methods ensure that GLFW is initialied before m_renderer and torn down after it. Then you do not even have to make the renderer a pointer and can embed the member directly (if that is feasible).