Context Events API

Declared in include/metagl/ContextEvents.hpp. Added in v0.2.0. The Context Events API provides an observer interface for GL context-lost and context-restored lifecycle events.

Overview

On mobile (Android) and in browsers (WebGL / Emscripten), the GPU context can be taken away at any time — the system kills it to free resources, or the browser tab loses focus. When this happens all GL handles (textures, buffers, shaders, programs, VAOs) become invalid. The context events system lets any object register a callback so it can clean up and later re-upload its GPU resources.

The context event system is separate from the raw MarkContextLost() / MarkContextRestored() functions in Context.hpp. The event system dispatches to all registered listeners; the raw functions only update the internal state flag.

ContextListener Interface

class ContextListener
{
public:
    virtual ~ContextListener() = default;

    // Called when the GL context has been lost.
    // WARNING: Do NOT call any metagl::gl* function from this callback.
    virtual void OnContextLost() {}

    // Called after the GL context has been restored and function pointers reloaded.
    // Safe to call metagl::gl* functions here to recreate GPU resources.
    virtual void OnContextRestored() {}
};

Warning: Inside OnContextLost() you must not call any metagl::gl* function. The context is already gone; all function pointers may be null or point to a dead context.

Registration

FunctionDescription
AddContextListener(ContextListener*) Register a listener. The caller retains ownership; pointer must stay valid until removed.
RemoveContextListener(ContextListener*) Unregister. No-op if not found. Call before the listener is destroyed.

Event Dispatch

FunctionDescription
NotifyContextLost() Dispatches OnContextLost() to all registered listeners, then calls MarkContextLost().
NotifyContextRestored() Dispatches OnContextRestored() to all registered listeners, then calls MarkContextRestored().

Required Call Order on Context Restore

After a context-restore event, you must follow this order:

  1. Call metagl::LoadCurrentContext(getProcAddress) — reloads all GL function pointers and redetects capabilities. No metagl::gl* call is safe before this step.
  2. Call metagl::NotifyContextRestored() — fires OnContextRestored() on all registered listeners so they can recreate GPU resources.

Undefined behaviour: calling NotifyContextRestored() before LoadCurrentContext() means listeners may invoke GL functions through stale or null function pointers.

Full Example

#include <metagl/metagl.hpp>

class MyRenderer : public metagl::ContextListener
{
public:
    bool init() {
        metagl::AddContextListener(this);
        return uploadResources();
    }

    ~MyRenderer() {
        metagl::RemoveContextListener(this);
    }

    void OnContextLost() override {
        // Don't call GL — just reset handles to 0
        texture_ = metagl::TextureId{};
        vao_     = metagl::VertexArrayId{};
        vbo_     = metagl::BufferId{};
        program_ = metagl::ProgramId{};
    }

    void OnContextRestored() override {
        // GL pointers are valid again — recreate everything
        uploadResources();
    }

private:
    bool uploadResources() {
        metagl::glGenTextures(1, &texture_.value);
        metagl::glBindTexture(metagl::TextureTarget::Texture2D, texture_);
        // ... upload pixel data ...
        return true;
    }

    metagl::TextureId     texture_;
    metagl::VertexArrayId vao_;
    metagl::BufferId      vbo_;
    metagl::ProgramId     program_;
};

// In main / application setup:
MyRenderer renderer;
metagl::Initialize(SDL_GL_GetProcAddress);
renderer.init();

// Platform context-loss path (e.g. Android onSurfaceDestroyed):
metagl::NotifyContextLost();

// Platform context-restore path (e.g. Android onSurfaceCreated):
metagl::LoadCurrentContext(SDL_GL_GetProcAddress); // step 1
metagl::NotifyContextRestored();                   // step 2

Android

On Android, context loss fires when the app goes to background (the EGL surface is destroyed). Wire up the callbacks from your GLSurfaceView.Renderer JNI calls:

// onSurfaceDestroyed (context lost):
metagl::NotifyContextLost();

// onSurfaceCreated (context restored or first-time creation):
bool ok = metagl::Initialize(eglGetProcAddress);   // first time
// or:
metagl::LoadCurrentContext(eglGetProcAddress);         // on restore
metagl::NotifyContextRestored();

WebGL / Emscripten

Use metagl/Emscripten.hpp to install browser event handlers automatically. After that, call NotifyContextLost / NotifyContextRestored from your own handler, or rely on the Emscripten callbacks to call MarkContextLost / MarkContextRestored directly.

#include <metagl/metagl.hpp>  // Emscripten.hpp included automatically

metagl::Initialize(emscripten_webgl_get_proc_address);
metagl::InstallEmscriptenContextLossCallbacks("#canvas");

// When context is restored, the browser fires webglcontextrestored.
// Inside your handler:
metagl::LoadCurrentContext(emscripten_webgl_get_proc_address);
metagl::NotifyContextRestored();