func main(f func(screen.Screen)) error { if tid := C.threadID(); tid != initThreadID { log.Fatalf("gldriver.Main called on thread %d, but gldriver.init ran on %d", tid, initThreadID) } mainCallback = f C.startDriver() return nil }
func main(f func(screen.Screen)) error { if gl.Version() == "GL_ES_2_0" { return errors.New("gldriver: ES 3 required on X11") } C.startDriver() glctx, worker = gl.NewContext() closec := make(chan struct{}) go func() { f(theScreen) close(closec) }() // heartbeat is a channel that, at regular intervals, directs the select // below to also consider X11 events, not just Go events (channel // communications). // // TODO: select instead of poll. Note that knowing whether to call // C.processEvents needs to select on a file descriptor, and the other // cases below select on Go channels. heartbeat := time.NewTicker(time.Second / 60) workAvailable := worker.WorkAvailable() for { select { case <-closec: return nil case ctx := <-glcontextc: // TODO: do we need to synchronize with seeing a size event for // this window's context before or after calling makeCurrent? // Otherwise, are we racing with the gl.Viewport call? I've // occasionally seen a stale viewport, if the window manager sets // the window width and height to something other than that // requested by XCreateWindow, but it's not easily reproducible. C.makeCurrent(C.uintptr_t(ctx)) case w := <-publishc: C.swapBuffers(C.uintptr_t(w.ctx.(uintptr))) w.publishDone <- screen.PublishResult{} case req := <-uic: ret := req.f() if req.retc != nil { req.retc <- ret } case <-heartbeat.C: C.processEvents() case <-workAvailable: worker.DoWork() } } }