#(zigglgen) seg fault unless I bind the proc threads every frame

1 messages · Page 1 of 1 (latest)

storm flower
#

I'm trying to learn openGL through zig but I ran into this issue where I end up with a seg fault unless I bind the proc threads every frame, my code is

pub const Renderer = struct {
    window: ?*c.SDL_Window,
    procs: gl.ProcTable,
    context: ?*c.struct_SDL_GLContextState,

    const Self = Renderer;


    pub fn new() !Renderer{
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        _ = c.SDL_GL_MakeCurrent(window, context);
        var procs: gl.ProcTable = undefined;
        if(!procs.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&procs);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
        return Renderer{
            .window = window,
            .procs = procs,
            .context = context
        };
    }

    pub fn render(self: Renderer) void{
        gl.makeProcTableCurrent(&self.procs);
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(self.window);
    }


    pub fn free(self: Renderer) void{
        c.SDL_DestroyWindow(self.window);
        _ = c.SDL_GL_DestroyContext(self.context);
        gl.makeProcTableCurrent(null);
    }
};
#

if I use this code instead

const Vertex_shader = "#version 330 core\n layout (location = 0) in vec3 aPos;\n void main()\n {\n gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n }"
;

    const Vertices = [_]f32{
        -0.5, -0.5, 0.0,
        0.5, -0.5, 0.0,
        0.0, 0.5, 0.0
    };

pub const Renderer = struct {
    window: ?*c.SDL_Window,
    procs: gl.ProcTable,
    context: ?*c.struct_SDL_GLContextState,

    const Self = Renderer;


    pub fn new() !Renderer{
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        _ = c.SDL_GL_MakeCurrent(window, context);
        var procs: gl.ProcTable = undefined;
        if(!procs.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&procs);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
        return Renderer{
            .window = window,
            .procs = procs,
            .context = context
        };
    }

    pub fn render(self: Renderer) void{
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(self.window);
    }


    pub fn free(self: Renderer) void{
        c.SDL_DestroyWindow(self.window);
        _ = c.SDL_GL_DestroyContext(self.context);
        gl.makeProcTableCurrent(null);
    }
};

it creates a seg fault whenever I call the clear color in the render loop

devout cedar
#

self: Renderer is taking a copy, when the function exits pointers to that copy are no longer valid, hence why you need to update them every time.
simply take a pointer instead self: *const Renderer, idk if it needs to be mutable or not.

I'm willing to bet this is the same issue with your seccond snippet, but it could also be something else. Idk enough about opengl to be certain.

#

Oops, I meant the pointer to procs in init is a local variable so its invalid after the function returns

#

got my self mixed up

novel canyon
#

Yeah there's 2 issues:

  1. Pointer to local variable of procs
  2. self: Renderer is copy, so your address to &self.procs isn't stable
storm flower
#

well after changing both procs and the self reference... I still get a seg fault

pub const Renderer = struct {
    window: ?*c.SDL_Window,
    procs: *gl.ProcTable,
    context: ?*c.struct_SDL_GLContextState,

    const Self = Renderer;


    pub fn new() !Renderer{
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        _ = c.SDL_GL_MakeCurrent(window, context);
        var procs: gl.ProcTable = undefined;
        if(!procs.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&procs);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
        return Renderer{
            .window = window,
            .procs = &procs,
            .context = context
        };
    }

    pub fn render(self: *const Renderer) void{
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(self.window);
    }


    pub fn free(self: *const Renderer) void{
        c.SDL_DestroyWindow(self.window);
        _ = c.SDL_GL_DestroyContext(self.context);
        gl.makeProcTableCurrent(null);
    }
};
novel canyon
#

do this instead:

pub const Renderer = struct {
    window: ?*c.SDL_Window,
    context: ?*c.struct_SDL_GLContextState,

    var _GL_PROCS: gl.ProcTable = undefined;
    const Self = Renderer;

    pub fn new() !Renderer{
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        _ = c.SDL_GL_MakeCurrent(window, context);
        if(!_GL_PROCS.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&_GL_PROCS);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
        return Renderer{
            .window = window,
            .context = context
        };
    }

    pub fn render(self: *const Renderer) void{
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(self.window);
    }


    pub fn free(self: *const Renderer) void{
        c.SDL_DestroyWindow(self.window);
        _ = c.SDL_GL_DestroyContext(self.context);
        gl.makeProcTableCurrent(null);
    }
};

This assumes that you don't use Renderer in other threads

#

if you want proc table to be a field, then you need to make proc table initialization a separate function, or use inplace init instead

devout cedar
storm flower
# novel canyon do this instead: ```rs pub const Renderer = struct { window: ?*c.SDL_Window,...

yeah still a seg fault, this is my app struct in case the issue lies there

pub const App = struct {

    renderer: renderer.Renderer,
    world: *flecs.world_t,
    var quit: bool = false;

    pub fn new() !App{
        _ = c.SDL_Init(c.SDL_INIT_GAMEPAD);
        const app = App{
            .renderer = try renderer.Renderer.new(),
            .world = flecs.init(),
        };
        return app;
    }

    pub fn run(self: App) void{
        defer self.deinit();
        self.main_loop();
    }

    fn main_loop(self: App) void{
        var event: c.SDL_Event = undefined;
        while (!quit){
            while (c.SDL_PollEvent(&event) != false) {
                switch (event.type) 
                {
                    c.SDL_EVENT_QUIT => self.deinit(),
                    else => {}
                }
            }
            self.renderer.render();
        }
    }
    pub fn deinit(self: App) void{
        quit = true;
        self.renderer.free();
        c.SDL_Quit();
    }
};
novel canyon
#

would need to see a stacktrace

storm flower
#

full stack trace is here, everything points to the moment I change the clear color in render

    return ProcTable.current.?.ClearColor(r, g, b, a);
                                         ^
C:\azure\VoxelProject\src\core\renderer\renderer.zig:50:22: 0x7ff682bb2902 in render (VoxelProject_zcu.obj)
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
                     ^
C:\azure\VoxelProject\src\core\app.zig:42:33: 0x7ff682bb015c in main_loop (VoxelProject_zcu.obj)
            self.renderer.render();
                                ^
C:\azure\VoxelProject\src\core\app.zig:29:23: 0x7ff682b9f926 in run (VoxelProject_zcu.obj)
        self.main_loop();
                      ^
C:\azure\VoxelProject\src\main.zig:7:12: 0x7ff682b9f8cf in main (VoxelProject_zcu.obj)
    app.run();
           ^
C:\Users\{user}\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\std\start.zig:602:28: 0x7ff682b9fbdd in main (VoxelProject_zcu.obj)
    return callMainWithArgs(@as(usize, @intCast(c_argc)), @as([*][*:0]u8, @ptrCast(c_argv)), envp);
                           ^
C:\Users\{user}\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\libc\mingw\crt\crtexe.c:259:0: 0x7ff682bbef6b in __tmainCRTStartup (crt2.obj)
    mainret = _tmain (argc, argv, envp);

C:\Users\{user}\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\libc\mingw\crt\crtexe.c:179:0: 0x7ff682bbefcb in mainCRTStartup (crt2.obj)
  ret = __tmainCRTStartup ();

???:?:?: 0x7ff9092e7373 in ??? (KERNEL32.DLL)
???:?:?: 0x7ff90abdcc90 in ??? (ntdll.dll)
run
└─ run exe VoxelProject failure
novel canyon
#

how does your renderer new look like now?

storm flower
#

just the new function currently looks like this

    pub fn new() !Renderer{
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        _ = c.SDL_GL_MakeCurrent(window, context);
        var procs: gl.ProcTable = undefined;
        if(!procs.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&procs);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
        return Renderer{
            .window = window,
            .procs = &procs,
            .context = context
        };
    }
novel canyon
#

that's still setting procs to a local variable

novel canyon
storm flower
#

okay yeah that fixes it (well until I go to exit, then it still seg faults)

novel canyon
#

alternative to not use a global is inplace init:

    pub fn init(self: *Renderer) !void {
        const window = c.SDL_CreateWindow("Voxel Project", 1280, 720, c.SDL_WINDOW_OPENGL);
        const context = c.SDL_GL_CreateContext(window);
        self.* = .{
          .window = window,
          .context = context,
          .procs = undefined,
        };

        _ = c.SDL_GL_MakeCurrent(window, context);
        if(!procs.init(c.SDL_GL_GetProcAddress)) return error.InitFailed;
        gl.makeProcTableCurrent(&renderer.procs);
        gl.Viewport(0, 0, 1280, 720);

        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);
        _ = c.SDL_GL_SwapWindow(window);
    }

and then you init renderer like this:

var renderer: Renderer = undefined;
try renderer.init();
novel canyon
storm flower
#

okay yeah that one is an easy fix

storm flower
# novel canyon yeah probably because you free the sdl window before killing context

no it somehow all goes back to the clear color

0x7ff7b6f7eee2 in ClearColor (VoxelProject_zcu.obj)
    return ProcTable.current.?.ClearColor(r, g, b, a);
                            ^
C:\azure\VoxelProject\src\core\renderer\renderer.zig:48:22: 0x7ff7b6f928c2 in render (VoxelProject_zcu.obj)
        gl.ClearColor(0.2, 0.3, 0.3, 1.0);
                     ^
C:\azure\VoxelProject\src\core\app.zig:43:33: 0x7ff7b6f90123 in main_loop (VoxelProject_zcu.obj)
            self.renderer.render();
                                ^
C:\azure\VoxelProject\src\core\app.zig:30:23: 0x7ff7b6f7f8c9 in run (VoxelProject_zcu.obj)
        self.main_loop();
                      ^
C:\azure\VoxelProject\src\main.zig:7:12: 0x7ff7b6f7f86a in main (VoxelProject_zcu.obj)
    app.run();
           ^
C:\Users\user\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\std\start.zig:602:28: 0x7ff7b6f7fb8d in main (VoxelProject_zcu.obj)
    return callMainWithArgs(@as(usize, @intCast(c_argc)), @as([*][*:0]u8, @ptrCast(c_argv)), envp);
                           ^
C:\Users\user\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\libc\mingw\crt\crtexe.c:259:0: 0x7ff7b6f9ef3b in __tmainCRTStartup (crt2.obj)
    mainret = _tmain (argc, argv, envp);

C:\Users\user\Downloads\zig-x86_64-windows-0.15.1\zig-x86_64-windows-0.15.1\lib\libc\mingw\crt\crtexe.c:179:0: 0x7ff7b6f9ef9b in mainCRTStartup (crt2.obj)
  ret = __tmainCRTStartup ();

???:?:?: 0x7ff9092e7373 in ??? (KERNEL32.DLL)
???:?:?: 0x7ff90abdcc90 in ??? (ntdll.dll)
run
└─ run exe VoxelProject failure

the current exit order is now

    pub fn deinit(self: *App) void{
        quit = true;
        self.renderer.free();
        c.SDL_Quit();
    }
    pub fn free(self: *const Renderer) void{
        _ = c.SDL_GL_DestroyContext(self.context);
        gl.makeProcTableCurrent(null);
        
        c.SDL_DestroyWindow(self.window);
    }
novel canyon
#

your main_loop calls self.deinit() but doesn't return from the function, thus self.renderer.render() is getting called after

#

you also may want to not copy App either in your methods, use self: *App or self: *const App instead

storm flower
#

yeah I already fixed the second one