change pixelgl, so that it runs on the main thread

This commit is contained in:
faiface 2016-11-25 17:12:13 +01:00
parent 2bc43c7ec4
commit 5043d06295
1 changed files with 32 additions and 13 deletions

View File

@ -7,23 +7,42 @@ import (
"github.com/go-gl/gl/v3.3-core/gl" "github.com/go-gl/gl/v3.3-core/gl"
) )
// Due to the existance and usage of thread-local variables by OpenGL, it's recommended to // Due to the limitations of OpenGL and operating systems, all OpenGL related calls must be done from the main thread.
// execute all OpenGL calls from a single dedicated thread. This file defines functions to make
// it possible.
var callQueue = make(chan func(), 32) var callQueue = make(chan func(), 32)
func init() { func init() {
runtime.LockOSThread()
}
// Run is essentialy the "main" function of the pixelgl package.
// Run this function from the main function (because that's guaranteed to run in the main thread).
//
// This function reserves the main thread for the OpenGL stuff and runs a supplied run function in a
// separate goroutine.
//
// Run returns when the provided run function finishes.
func Run(run func()) {
done := make(chan struct{})
go func() { go func() {
runtime.LockOSThread() run()
for f := range callQueue { close(done)
f()
}
}() }()
loop:
for {
select {
case f := <-callQueue:
f()
case <-done:
break loop
}
}
} }
// Init initializes OpenGL by loading the function pointers from the active OpenGL context. // Init initializes OpenGL by loading the function pointers from the active OpenGL context.
// This function must be manually run inside the dedicated thread (Do, DoErr, DoVal, etc.). // This function must be manually run inside the main thread (Do, DoErr, DoVal, etc.).
// //
// It must be called under the presence of an active OpenGL context, e.g., always after calling window.MakeContextCurrent(). // It must be called under the presence of an active OpenGL context, e.g., always after calling window.MakeContextCurrent().
// Also, always call this function when switching contexts. // Also, always call this function when switching contexts.
@ -34,13 +53,13 @@ func Init() {
} }
} }
// DoNoBlock executes a function inside a dedicated OpenGL thread. // DoNoBlock executes a function inside the main OpenGL thread.
// DoNoBlock does not wait until the function finishes. // DoNoBlock does not wait until the function finishes.
func DoNoBlock(f func()) { func DoNoBlock(f func()) {
callQueue <- f callQueue <- f
} }
// Do executes a function inside a dedicated OpenGL thread. // Do executes a function inside the main OpenGL thread.
// Do blocks until the function finishes. // Do blocks until the function finishes.
// //
// All OpenGL calls must be done in the dedicated thread. // All OpenGL calls must be done in the dedicated thread.
@ -53,7 +72,7 @@ func Do(f func()) {
<-done <-done
} }
// DoErr executes a function inside a dedicated OpenGL thread and returns an error to the called. // DoErr executes a function inside the main OpenGL thread and returns an error to the called.
// DoErr blocks until the function finishes. // DoErr blocks until the function finishes.
// //
// All OpenGL calls must be done in the dedicated thread. // All OpenGL calls must be done in the dedicated thread.
@ -65,10 +84,10 @@ func DoErr(f func() error) error {
return <-err return <-err
} }
// DoVal executes a function inside a dedicated OpenGL thread and returns a value to the caller. // DoVal executes a function inside the main OpenGL thread and returns a value to the caller.
// DoVal blocks until the function finishes. // DoVal blocks until the function finishes.
// //
// All OpenGL calls must be done in the dedicated thread. // All OpenGL calls must be done in the main thread.
func DoVal(f func() interface{}) interface{} { func DoVal(f func() interface{}) interface{} {
val := make(chan interface{}) val := make(chan interface{})
callQueue <- func() { callQueue <- func() {