#OpenGL functions point to null when hot reloading DLL.

1 messages · Page 1 of 1 (latest)

shy kraken
#

I have two files: lib/lib.odin and main.odin.

lib.odin has the following relevant code:

GameState :: struct {
    vbo: u32,
    vao: u32,
    ebo: u32,
    verts: []f32,
}

g: ^GameState

@(export)
game_init :: proc() {
    g = new(GameState)

    g.verts = []f32 {
         0.0,   0.3, 1.0, 0.0, 0.0,
        -0.3,  -0.3, 0.0, 1.0, 0.0,
         0.3,  -0.3, 0.0, 0.0, 1.0,
    }


    gl.GenBuffers(1, &g.vbo)
    // extra lines excluded
}

@(export)
game_init_window :: proc() {
    if !glfw.Init() do return

    glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 4)
    glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 6)
    glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
    when ODIN_DEBUG {
        glfw.WindowHint(glfw.OPENGL_DEBUG_CONTEXT, gl.TRUE)
    }

    window = glfw.CreateWindow(WIN_WIDTH, WIN_HEIGHT, "OdinLearnOpenGL", nil, nil)
    // win error check
    glfw.MakeContextCurrent(window)
    gl.load_up_to(4, 6, glfw.gl_set_proc_address)
}

lib/lib.odin is compiled with the following build command:
odin build lib -build-mode:dll -debug -out:build/debug.dll -source-code-locations:normal -subsystem:console

In main.odin, I have the following, which is mostly copied from Karl Zylinski's hot reload template:

GameAPI :: struct {
        lib: dynlib.Library,
        init_window: proc(),
        destroy_window: proc(),
        init: proc(),
        update: proc(),
        get_state: proc() -> rawptr,
        set_state: proc(mem: rawptr),
        should_run: proc() -> b32
}
main :: proc() {
  // some setup code for the tracking allocator and calling the GameAPI::init_window and init functions...
  for game_api.should_run() {
    game_api.update()
    if game_api.force_reload() {
        new_game_api := load_game_api(game_api_version)
        append(&old_game_apis, game_api)
        game_memory := game_api.get_state()
        game_api = new_game_api 
        game_api.set_state(game_memory)
    }    
  }                    
}
#

Follow up since I hit the character limit:
When attempting the hot reload, I then get this error as seen in the screenshot. I am not sure as to why hot reloading the DLL causes the OpenGL functions to point to null.

#

I have tried figuring it out on my own but to no avail; I would like to know the details on why exactly this is happening though

#

very interesting problem

#

My only guess so far is that the newly copied DLL loses its link with the system libraries required to make the OpenGL API calls

hollow ibex
#

All of the OpenGL function pointers are stored in globals, those will be local to the code using it (i.e. the DLL)

shy kraken
#

So when I recompile the DLL and then try having my GameAPI struct point to the new DLL, the new DLL doesn't have the reference to the global table of OpenGL function pointers?:

hollow ibex
#

The global variables that the DLL uses are stored in the DLL's memory, a separate DLL will have a separate set of globals

shy kraken
#

Meaning that I would need to do the necessary GLFW and GL initialization in the main.odin file so that I can keep the GLFW and GL global pointers consistent

#

If i am thinking about this correctly

hollow ibex
#

Anything you're storing in globals, and also static libraries. If you build with -define:GLFW_SHARED=true, then GLFW itself will be shared between the application and any loaded DLLs, but you'll also need to copy the GLFW DLL to the application directory. You'll still need to handle the OpenGL function pointers, and any other globals in your DLL

#

For the OpenGL function pointers, you can just gl.load_up_to again

shy kraken
#

I did copy over the glfw3.dll file into the same directory as the exe file loading the DLL, and attempting a hot reload triggers an error on checking for glfw.WindowShouldClose(window) (the window variable is local to the DLL)

hollow ibex
#

Does the host application use GLFW at all? Or is it only the DLL?

shy kraken
#

only the DLL

hollow ibex
#

If the window pointer is stored in a global in the DLL, then yeah, you'll need some way to "transfer" it to the new DLL

shy kraken
#

host application is simply loading the DLL and calling the functions I exposed

#

Okay this makes sense now

#

I got the reloading to occur without getting those null pointer errors