看看这个用 Go 编写的超级简单的小测试用例 OpenGL 程序:
package main
import (
"runtime"
"./glfw"
gl "github.com/chsc/gogl/gl21"
)
func onExit (err error) {
glfw.Terminate()
if err != nil { panic(err) }
}
func main () {
runtime.LockOSThread()
err := glfw.Init()
if err != nil { panic(err) }
err = glfw.OpenWindow(1280, 720, 0, 0, 0, 0, 0, 0, glfw.Windowed)
if err != nil { onExit(err) }
err = gl.Init()
if err != nil || gl.GetError() != 0 { onExit(err) }
for glfw.WindowParam(glfw.Opened) == 1 {
gl.Viewport(0, 0, 1280, 720)
gl.ClearColor(1, 0, 0, 1)
gl.Clear(gl.COLOR_BUFFER_BIT) // THE CRASH
gl.Begin(gl.TRIANGLES)
gl.Color3f(1, 0, 0)
gl.Vertex3f(-1, -1, 0)
gl.Color3f(0, 1, 0)
gl.Vertex3f(0, 1, 0)
gl.Color3f(0, 0, 1)
gl.Vertex3f(1, -1, 0)
gl.End()
glfw.SwapBuffers()
if glfw.Key(glfw.KeyEsc) == 1 {
glfw.CloseWindow()
}
}
onExit(nil)
}
这在带有 Go 1.0.1 64 位的 Windows 7 64 位下构建良好。
如果您取出(或注释掉)gl.Clear(gl.COLOR_BUFFER_BIT)行,它也可以正常工作(OpenGL 绘制一个彩虹色的 2D 三角形,直到窗口关闭) 。
但是,只要调用 gl.Clear(无论传递什么参数),它都会崩溃,Windows 会通知我“glfw-win.exe 已停止工作......”并且 Windows 事件查看器为我提供以下错误日志:
Faulting application name: glfw-win.exe, version: 0.0.0.0, time stamp: 0x4f9f5ec5
Faulting module name: glfw-win.exe, version: 0.0.0.0, time stamp: 0x4f9f5ec5
Exception code: 0xc0000005
Fault offset: 0x0000000000012883
Faulting process id: 0xd4c
Faulting application start time: 0x01cd274e4c69a3d3
Faulting application path: C:\mytmp\glfw-win\glfw-win.exe
Faulting module path: C:\mytmp\glfw-win\glfw-win.exe
Report Id: 8a5bacc0-9341-11e1-911a-d067e544ad7f
现在,有几个值得注意的点...
glfw包只是一个自定义包,它公开与github.com/jteeuwen/glfw完全相同的 API,但在内部使用 LoadLibrary/GetProcAddress 来使用 glfw.dll 而不是编译时 CGO/GCC/LD 链接——因为后者不能可悲的是,它可以在 64 位 Windows 中工作,不确定是 mingw64 还是 gcc 还是 cgo 是罪魁祸首。使用 LoadLibrary/GetProcAddress 调用我的 glfw.dll 的自定义 64 位版本运行良好。显然这里的问题是调用 gl 包,而不是 glfw。
gl包确实就是这个,未经修改。我尝试了一些 LDFLAGS 修改,例如 -m64 -lmingw32 -Wl,/windows/opengl32.dll 等,但没有区别,只要不调用 gl.Clear(),原始工作与修改后的工作一样好,所以我恢复到原来的。当然,稍后我将继续使用 OpenGL 4.2。
使用 Process Explorer,我可以看到我的进程是 64 位的,并且所有加载的 DLL 也是 64 位图像(包括 opengl32.dll 和 glfw.dll)。
“难道是gl21包无法为opengl32.dll导出的glClear()函数获取有效地址?” -- 不太可能:根据第 2926 行,如果是这种情况,我对 gl.Init() 的调用将失败。
GPU驱动问题?更不可能了。安装了最新的官方 nVidia Quadro 5010M 驱动程序 296.35。还尝试了“性能驱动程序”,但无论如何似乎是完全相同的驱动程序。根据 nVidia 控制面板的完整 OpenGL 4.2 支持(尽管 opengl32.dll 的日期为 2009 年——无论如何,我目前的目标是 2.1)。此外,“Geeks3D GPU Caps Viewer”和“Shader Toy Mark”中的 OpenGL 着色器运行,正如 GLFW 示例程序particles.exe 一样——它们都使用 glClear()。
使用 gl42 而不是 gl21 时会发生完全相同的问题,所以这也不是原因。
请注意在此示例中所有其他 gl.SomeExportedFunc() 调用如何不会崩溃...
该怎么做,如何进行?
如果这只发生在 gl.Clear() 而没有其他函数,我可以忍受这个——无论如何,我只是用自定义内容渲染全屏四边形——但我在这里测试 Win64 相当早(得到许多 gl42 代码在 Linux64 下工作得很好,现在即将“移植”到 Win64),我担心以后进一步的调用会暴露同样的问题,所以我现在报告这个。我很快就会发现哪些其他电话会受到此影响。