加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

opengl – Golang fmt.Println()导致游戏崩溃

发布时间:2020-12-16 19:04:16 所属栏目:大数据 来源:网络整理
导读:我在Go中有这个简单的OpenGL程序. 当我编译并运行它时,主游戏循环在崩溃之前会经历大约9次迭代. rendering for the 0 timerendering for the 1 timerendering for the 2 timerendering for the 3 timerendering for the 4 timerendering for the 5 timerende
我在Go中有这个简单的OpenGL程序.

当我编译并运行它时,主游戏循环在崩溃之前会经历大约9次迭代.

rendering for the  0  time
rendering for the  1  time
rendering for the  2  time
rendering for the  3  time
rendering for the  4  time
rendering for the  5  time
rendering for the  6  time
SIGSEGV: segmentation violation
PC=0x7fdab95a0e29
signal arrived during cgo execution

runtime.cgocall(0x414f90,0x7fdab9887e88)
    /usr/lib/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fdab9887e70
github.com/go-gl/gl._Cfunc_glClear(0xc200004100)
    github.com/go-gl/gl/_obj/_cgo_defun.c:340 +0x31 fp=0x7fdab9887e88
github.com/go-gl/gl.Clear(0x4100)
    /mnt/data/Dropbox/Coding/Go/src/github.com/go-gl/gl/gl.go:161 +0x25 fp=0x7fdab9887e98
main.draw()
    /home/josh/Coding/Go/src/github.com/JoshWillik/Wander/wander.go:120 +0x25 fp=0x7fdab9887eb8
main.main()
    /home/josh/Coding/Go/src/github.com/JoshWillik/Wander/wander.go:52 +0x300 fp=0x7fdab9887f48
runtime.main()
    /usr/lib/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fdab9887fa0
runtime.goexit()
    /usr/lib/go/src/pkg/runtime/proc.c:1394 fp=0x7fdab9887fa8

goroutine 3 [syscall]:
runtime.goexit()
    /usr/lib/go/src/pkg/runtime/proc.c:1394

rax     0x0
rbx     0x7fdab9887e88
rcx     0x7fdab9887e88
rdx     0x7fdab9887e20
rdi     0x4100
rsi     0xc210001900
rbp     0xc21002a000
rsp     0x7fdab2a4ddd8
r8      0xc210001120
r9      0x7fdab9887e20
r10     0x0
r11     0x286
r12     0x0
r13     0x7fdab9a74000
r14     0x0
r15     0x7fdab2a4e700
rip     0x7fdab95a0e29
rflags  0x10202
cs      0x33
fs      0x0
gs      0x0

如果我删除了shouldRender函数中基于时间的逻辑,那么它会在崩溃之前进行大约28-29次迭代.

如果我在draw函数中删除对gl.Clear()的调用,它会在崩溃前持续到90s.

如果我在shouldRender中删除对fmt.Println()的调用,游戏将按预期运行而不会崩溃. (我已经测试了大约2或3分钟,所以差不多有1万帧)

这让我怀疑对fmt.Println()的调用在某种程度上导致了分段违规.我误读了这些迹象吗?如果没有,像Println()这样的核心功能如何不稳定?

package main

import (
    f "fmt"
    "github.com/go-gl/gl"
    glfw "github.com/go-gl/glfw3"
    "math"
    "time"
)

var (
    numRendered = 0
    lastDraw = time.Now()
    fps = 60
    seconds = time.Now()
    attr gl.AttribLocation
)

func main(){
    if !glfw.Init(){
        f.Println("Failed to init glfw")
        panic("Cannot initialize glfw library")
    }
    defer glfw.Terminate()

    //glfw.WindowHint(glfw.DepthBits,16)
    window,err := glfw.CreateWindow(300,300,"Wander",nil,nil)
    if err != nil{
        panic(err)
    }

    window.SetFramebufferSizeCallback(reshape)
    window.SetKeyCallback(key)
    window.MakeContextCurrent()
    glfw.SwapInterval(1)
    width,height := window.GetFramebufferSize()
    reshape(window,width,height)

    if gl.Init() != 0 {
        panic("Failed to init GL")
    }

    prog := setupProgram()
    defer prog.Delete()
    prog.Use()

    attr = prog.GetAttribLocation("offset")

    setup()
    for !window.ShouldClose() {
        if shouldRender(){
            draw()
        }
        animate()
        window.SwapBuffers()
        glfw.PollEvents()
    }
}
func setupProgram()(prog gl.Program){
    vertexSource := `
        #version 430 core

        layout (location = 0) in vec4 offset;

        const vec4 vertecies[3] = vec4[3](
            vec4(0.25,0.5,1.0),vec4(-0.25,-0.5,1.0)
        );

        void main(){
            gl_Position = vertecies[gl_VertexID] + offset;
        }`
    fragmentSource := `
        #version 430 core

        out vec4 color;

        void main(){
            color = vec4(1.0,0.0,0.0); // red,blue,green,??
        }`
    vert,frag := gl.CreateShader(gl.VERTEX_SHADER),gl.CreateShader(gl.FRAGMENT_SHADER)
    defer vert.Delete()
    defer frag.Delete()
    vert.Source(vertexSource)
    frag.Source(fragmentSource)
    vert.Compile()
    frag.Compile()

    prog = gl.CreateProgram()
    prog.AttachShader(vert)
    prog.AttachShader(frag)
    prog.Link()
    prog.Use()
    f.Println(prog.GetInfoLog())

    return
}

func key(window *glfw.Window,k glfw.Key,s int,action glfw.Action,mods glfw.ModifierKey) {
    if action != glfw.Press {
        return
    }

    switch glfw.Key(k){
        case glfw.KeyEscape:
            window.SetShouldClose(true);
        default:
            return
    }
}

func reshape(window *glfw.Window,height int){
    gl.Viewport(0,height)
}
func draw(){
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.DrawArrays(gl.TRIANGLES,3)
}
func shouldRender() bool{
    if int(time.Since(lastDraw) * time.Second) >= 1000/fps{
        //f.Println("rendering for the ",numRendered," time")
        numRendered++
        lastDraw = time.Now()
        return true
    }

    return false;
}

func animate(){
    now := float64(time.Since(seconds))

    offset := [4]float32{
        float32(math.Sin(now)),float32(math.Cos(now)),0.0}
    attr.Attrib4fv(&offset)

    red := gl.GLclampf(math.Sin(now) * 0.25 + 0.75)
    blue := gl.GLclampf(math.Cos(now) * 0.25 + 0.75)
    green := gl.GLclampf(time.Since(seconds))
    _ = green;

    gl.ClearColor(red,0.2,0.0)
}
我在我的机器上运行你的代码 – 在64位Windows上运行MinGW-w64.虽然我的println代码比你的代码运行时间长(崩溃前超过30k的调用)但我观察到了同样的行为.

堆栈跟踪在调用gl函数时报告它,这给了我一个暗示:可能错误与OpenGL上下文有关.

的确,如果加上

import (
//...
"runtime"
//...
)

和线

runtime.LockOSThread()

在主函数的顶部,错误消失(或者至少在线程锁定它在我的机器上运行了几分钟,显然我无法证明它永远不会崩溃).

当Goroutines被阻止执行某些任务(如IO)时,Go运行时会偶尔拆分额外的线程以保持程序移动.

我怀疑它发生的事情是,有时在调用Println时,Goroutine在系统调用中被阻止,因此运行时通过在不同的线程上运行主goroutine来“帮助”你.由于OpenGL上下文绑定到一个线程,这导致您的程序在GL调用上崩溃,因为您正在调用错误的线程.

将runtime.LockOSThread()添加到main的顶部会强制主Goroutine始终在同一个线程上执行,从而将所有GL调用保持在正确的上下文中.

我应该补充一点,我简要地浏览了fmt软件包的源代码,从我看到的我无法证明goroutine / thread废话肯定会发生;但是,我强烈怀疑这是基于我对Go运行时的了解以及LockOSThread似乎修复它的事实.

无论哪种方式:当您使用OpenGL或OpenAL等C库时,依赖于将上下文绑定到单个线程,请确保始终使用runtime.LockOSThread将其运行的Goroutine锁定到一个线程.

更新:我在the Go scheduler找到了这个文件,如果我正确地阅读它,证实了我的怀疑.诸如打印之类的系统调用可以调用生成的新线程,以允许在IO上阻止程序时继续调用goroutine.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读