go-gl / gl

Go bindings for OpenGL (generated via glow)
MIT License
1.06k stars 72 forks source link

Error when binding in loop #157

Closed EliiasG closed 11 months ago

EliiasG commented 11 months ago

I tried making something combining learnopengl and the 4.1 example and the following code works, however when i uncomment any the of the commented out function calls in the render loop my program will crash with a weird error. I also tried checking for errors when linking the shader, it is still broken

package main

import (
    "log"
    "strings"

    "github.com/go-gl/gl/v3.3-core/gl"
    "github.com/go-gl/glfw/v3.3/glfw"
)

func main() {
    // init glfw
    if err := glfw.Init(); err != nil {
        log.Fatalln("failed to initialize glfw:", err)
    }
    defer glfw.Terminate()

    // init window
    glfw.WindowHint(glfw.ContextVersionMajor, 3)
    glfw.WindowHint(glfw.ContextVersionMinor, 3)
    glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
    // tutorial says required for mac
    glfw.WindowHint(glfw.OpenGLForwardCompatible, gl.TRUE)

    window, err := glfw.CreateWindow(800, 600, "LearnOpenGL in Go", nil, nil)
    if err != nil {
        panic(err)
    }
    window.MakeContextCurrent()

    // init gl (Glow)
    if err := gl.Init(); err != nil {
        panic(err)
    }

    // setup gl
    gl.Viewport(0, 0, 800, 600)

    // handle window resizing
    window.SetFramebufferSizeCallback(SizeChanged)

    // shaders
    vertexSource := `
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}` + "\x00"

    fragmentSource := `
#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}` + "\x00"
    var vertexShader uint32
    vertexShader = gl.CreateShader(gl.VERTEX_SHADER)
    csources, free := gl.Strs(vertexSource)
    gl.ShaderSource(vertexShader, 1, csources, nil)
    free()
    gl.CompileShader(vertexShader)

    checkShader(vertexShader)

    var fragmentShader uint32
    fragmentShader = gl.CreateShader(gl.FRAGMENT_SHADER)
    csources, free = gl.Strs(fragmentSource)
    gl.ShaderSource(fragmentShader, 1, csources, nil)
    free()
    gl.CompileShader(fragmentShader)

    checkShader(fragmentShader)

    // combine shaders
    var shaderProg uint32
    shaderProg = gl.CreateProgram()
    gl.AttachShader(shaderProg, vertexShader)
    gl.AttachShader(shaderProg, fragmentShader)
    gl.LinkProgram(shaderProg)

    // delete shaders
    gl.DeleteShader(vertexShader)
    gl.DeleteShader(fragmentShader)

    vertices := []float32{
        -0.5, -0.5, 0.0,
        0.5, -0.5, 0.0,
        0.0, 0.5, 0.0,
    }

    var vbo, vao uint32
    gl.GenVertexArrays(1, &vao)
    gl.GenBuffers(1, &vbo)

    gl.BindVertexArray(vao)

    gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
    gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, gl.Ptr(vertices), gl.STATIC_DRAW)

    gl.VertexAttribPointerWithOffset(0, 3, gl.FLOAT, false, 3*4, 0)
    gl.EnableVertexAttribArray(0)

    gl.BindBuffer(gl.ARRAY_BUFFER, 0)
    //gl.BindVertexArray(0)
    gl.UseProgram(shaderProg)
    // frame loop
    for !window.ShouldClose() {
        processInput(window)

        gl.ClearColor(0.2, 0.3, 0.3, 1.0)
        gl.Clear(gl.COLOR_BUFFER_BIT)

        //gl.UseProgram(shaderProg)
        //gl.BindVertexArray(vao)
        gl.DrawArrays(gl.TRIANGLES, 0, 3)

        window.SwapBuffers()
        glfw.PollEvents()
    }
}

func SizeChanged(w *glfw.Window, width, height int) {
    gl.Viewport(0, 0, int32(width), int32(height))
}

func processInput(w *glfw.Window) {
    if w.GetKey(glfw.KeyEscape) == glfw.Press {
        w.SetShouldClose(true)
    }
}

func checkShader(shader uint32) {
    var status int32
    gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
    if status == gl.FALSE {
        var logLength int32
        gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)

        log := strings.Repeat("\x00", int(logLength+1))
        gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
        print(log)
        panic("")
    }
}

The error

Exception 0xc0000005 0x0 0xe90 0x7ffcf4e9d1e9
PC=0x7ffcf4e9d1e9
signal arrived during external code execution

runtime.cgocall(0x7ff6fa6ecc4b, 0xc00011bce0)
    C:/Program Files/Go/src/runtime/cgocall.go:157 +0x4a fp=0xc00011bcb0 sp=0xc00011bc78 pc=0x7ff6fa5e48ea
github.com/go-gl/gl/v3.3-core/gl._Cfunc_glowUseProgram(0x7ffcf4cbd820, 0x3)
    _cgo_gotypes.go:22058 +0x4e fp=0xc00011bce0 sp=0xc00011bcb0 pc=0x7ff6fa69e16e
github.com/go-gl/gl/v3.3-core/gl.UseProgram(0x3)
    C:/Users/*****/go/pkg/mod/github.com/go-gl/gl@v0.0.0-20211210172815-726fda9656d6/v3.3-core/gl/package.go:13033 +0x2c fp=0xc00011bd00 sp=0xc00011bce0 pc=0x7ff6fa69fecc
main.main()
    c:/Projects/Go/LearnOpenGL/main.go:116 +0x7d8 fp=0xc00011bf80 sp=0xc00011bd00 pc=0x7ff6fa6c2698
runtime.main()
    C:/Program Files/Go/src/runtime/proc.go:250 +0x1be fp=0xc00011bfe0 sp=0xc00011bf80 pc=0x7ff6fa61e93e
runtime.goexit()
    C:/Program Files/Go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc00011bfe8 sp=0xc00011bfe0 pc=0x7ff6fa648321

goroutine 2 [force gc (idle)]:
runtime.gopark(0x7ff6fa75aad8, 0x7ff6fa80d750, 0x11, 0x14, 0x1)
    C:/Program Files/Go/src/runtime/proc.go:381 +0xfd fp=0xc000055f88 sp=0xc000055f58 pc=0x7ff6fa61edbd
runtime.goparkunlock(0x0?, 0x0?, 0x0?, 0x0?)
    C:/Program Files/Go/src/runtime/proc.go:387 +0x2a fp=0xc000055fb8 sp=0xc000055f88 pc=0x7ff6fa61ee4a
runtime.forcegchelper()
    C:/Program Files/Go/src/runtime/proc.go:305 +0xb0 fp=0xc000055fe0 sp=0xc000055fb8 pc=0x7ff6fa61eb90
runtime.goexit()
    C:/Program Files/Go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000055fe8 sp=0xc000055fe0 pc=0x7ff6fa648321
created by runtime.init.6
    C:/Program Files/Go/src/runtime/proc.go:293 +0x25

goroutine 3 [GC sweep wait]:
runtime.gopark(0x7ff6fa75aad8, 0x7ff6fa80d8a0, 0xc, 0x14, 0x1)
    C:/Program Files/Go/src/runtime/proc.go:381 +0xfd fp=0xc000057f58 sp=0xc000057f28 pc=0x7ff6fa61edbd
runtime.goparkunlock(0x0?, 0x0?, 0x0?, 0x0?)
    C:/Program Files/Go/src/runtime/proc.go:387 +0x2a fp=0xc000057f88 sp=0xc000057f58 pc=0x7ff6fa61ee4a
runtime.bgsweep(0x0?)
    C:/Program Files/Go/src/runtime/mgcsweep.go:278 +0x98 fp=0xc000057fc8 sp=0xc000057f88 pc=0x7ff6fa606ef8
runtime.gcenable.func1()
    C:/Program Files/Go/src/runtime/mgc.go:178 +0x26 fp=0xc000057fe0 sp=0xc000057fc8 pc=0x7ff6fa5fb4e6
runtime.goexit()
    C:/Program Files/Go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000057fe8 sp=0xc000057fe0 pc=0x7ff6fa648321
created by runtime.gcenable
    C:/Program Files/Go/src/runtime/mgc.go:178 +0x6b

goroutine 4 [GC scavenge wait]:
runtime.gopark(0x7ff6fa75aad8, 0x7ff6fa80d9a0, 0xd, 0x14, 0x2)
    C:/Program Files/Go/src/runtime/proc.go:381 +0xfd fp=0xc000065f48 sp=0xc000065f18 pc=0x7ff6fa61edbd
runtime.goparkunlock(0x7ff6fa75f420?, 0x1?, 0x0?, 0x0?)
    C:/Program Files/Go/src/runtime/proc.go:387 +0x2a fp=0xc000065f78 sp=0xc000065f48 pc=0x7ff6fa61ee4a
runtime.(*scavengerState).park(0x7ff6fa80d9a0)
    C:/Program Files/Go/src/runtime/mgcscavenge.go:400 +0x4b fp=0xc000065fa0 sp=0xc000065f78 pc=0x7ff6fa6049ab
runtime.bgscavenge(0x0?)
    C:/Program Files/Go/src/runtime/mgcscavenge.go:628 +0x45 fp=0xc000065fc8 sp=0xc000065fa0 pc=0x7ff6fa604f85
runtime.gcenable.func2()
    C:/Program Files/Go/src/runtime/mgc.go:179 +0x26 fp=0xc000065fe0 sp=0xc000065fc8 pc=0x7ff6fa5fb486
runtime.goexit()
    C:/Program Files/Go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000065fe8 sp=0xc000065fe0 pc=0x7ff6fa648321
created by runtime.gcenable
    C:/Program Files/Go/src/runtime/mgc.go:179 +0xaa

goroutine 5 [finalizer wait]:
runtime.gopark(0x7ff6fa75a978, 0x7ff6fa862580, 0x10, 0x14, 0x1)
    C:/Program Files/Go/src/runtime/proc.go:381 +0xfd fp=0xc000059e28 sp=0xc000059df8 pc=0x7ff6fa61edbd
runtime.runfinq()
    C:/Program Files/Go/src/runtime/mfinal.go:193 +0x107 fp=0xc000059fe0 sp=0xc000059e28 pc=0x7ff6fa5fa547
runtime.goexit()
    C:/Program Files/Go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000059fe8 sp=0xc000059fe0 pc=0x7ff6fa648321
created by runtime.createfing
    C:/Program Files/Go/src/runtime/mfinal.go:163 +0x50
rax     0x0
rbx     0xc00011bce0
rcx     0x3
rdi     0xc00011bce0
rsi     0xc000052820
rbp     0x36737ff5f0
rsp     0x36737ff5c8
r8      0xc00000cc00
r9      0x0
r10     0xa201879b5e5a7b70
r11     0x246
r12     0xc00011bac8
r13     0x0
r14     0xc000052000
r15     0x2030
rip     0x7ffcf4e9d1e9
rflags  0x10202
cs      0x33
fs      0x53
gs      0x2b
dmitshur commented 11 months ago

This may not be enough to fix the problem, but that code is missing a call to lock the execution of goroutine that runs the main function to the main OS thread. Trying to use GLFW or OpenGL without doing that will cause non-deterministic problems. See https://pkg.go.dev/runtime#LockOSThread docs:

All init functions are run on the startup thread. Calling LockOSThread from an init function will cause the main function to be invoked on that thread.

A goroutine should call LockOSThread before calling OS services or non-Go library functions that depend on per-thread state.

That is, the code above needs to also have:

func init() { runtime.LockOSThread() }
EliiasG commented 11 months ago

Oh thank you, i think it is fixed now.