Example #1
0
// loop is the primary drawing loop.
//
// After Cocoa has captured the initial OS thread for processing Cocoa
// events in runApp, it starts loop on another goroutine. It is locked
// to an OS thread for its OpenGL context.
//
// The loop processes GL calls until a publish event appears.
// Then it runs any remaining GL calls and flushes the screen.
//
// As NSOpenGLCPSwapInterval is set to 1, the call to CGLFlushDrawable
// blocks until the screen refresh.
func (a *app) loop(ctx C.GLintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(ctx)

	workAvailable := a.worker.WorkAvailable()

	for {
		select {
		case <-workAvailable:
			a.worker.DoWork()
		case <-theApp.publish:
		loop1:
			for {
				select {
				case <-workAvailable:
					a.worker.DoWork()
				default:
					break loop1
				}
			}
			C.CGLFlushDrawable(C.CGLGetCurrentContext())
			theApp.publishResult <- PublishResult{}
			select {
			case drawDone <- struct{}{}:
			default:
			}
		}
	}
}
Example #2
0
// drawLoop is the primary drawing loop.
//
// After Cocoa has created an NSWindow and called prepareOpenGL,
// it starts drawLoop on a locked goroutine to handle OpenGL calls.
//
// The screen is drawn every time a paint.Event is received, which can be
// triggered either by the user or by Cocoa via drawgl (for example, when
// the window is resized).
func drawLoop(w *windowImpl, vba uintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(C.uintptr_t(w.ctx))

	// Starting in OS X 10.11 (El Capitan), the vertex array is
	// occasionally getting unbound when the context changes threads.
	//
	// Avoid this by binding it again.
	C.glBindVertexArray(C.GLuint(vba))
	if errno := C.glGetError(); errno != 0 {
		panic(fmt.Sprintf("gldriver: glBindVertexArray failed: %d", errno))
	}

	workAvailable := w.worker.WorkAvailable()

	// TODO(crawshaw): exit this goroutine on Release.
	for {
		select {
		case <-workAvailable:
			w.worker.DoWork()
		case <-w.publish:
		loop:
			for {
				select {
				case <-workAvailable:
					w.worker.DoWork()
				default:
					break loop
				}
			}
			C.flushContext(C.uintptr_t(w.ctx))
			w.publishDone <- screen.PublishResult{}
		}
	}
}
Example #3
0
// loop is the primary drawing loop.
//
// After Cocoa has captured the initial OS thread for processing Cocoa
// events in runApp, it starts loop on another goroutine. It is locked
// to an OS thread for its OpenGL context.
//
// Two Cocoa threads deliver draw signals to loop. The primary source of
// draw events is the CVDisplayLink timer, which is tied to the display
// vsync. Secondary draw events come from [NSView drawRect:] when the
// window is resized.
func loop(ctx C.GLintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(ctx)
	var worker gl.Worker
	glctx, worker = gl.NewContext()

	workAvailable := worker.WorkAvailable()
	for {
		select {
		case <-workAvailable:
			worker.DoWork()
		case <-draw:
		loop1:
			for {
				select {
				case <-workAvailable:
					worker.DoWork()
				case <-theApp.publish:
					C.CGLFlushDrawable(C.CGLGetCurrentContext())
					theApp.publishResult <- PublishResult{}
					break loop1
				}
			}
			drawDone <- struct{}{}
		}
	}
}
Example #4
0
// loop is the primary drawing loop.
//
// After UIKit has captured the initial OS thread for processing UIKit
// events in runApp, it starts loop on another goroutine. It is locked
// to an OS thread for its OpenGL context.
func (a *app) loop(ctx C.GLintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(ctx)

	workAvailable := a.worker.WorkAvailable()

	for {
		select {
		case <-workAvailable:
			a.worker.DoWork()
		case <-theApp.publish:
		loop1:
			for {
				select {
				case <-workAvailable:
					a.worker.DoWork()
				default:
					break loop1
				}
			}
			C.swapBuffers(ctx)
			theApp.publishResult <- PublishResult{}
		}
	}
}
Example #5
0
// loop is the primary drawing loop.
//
// After Cocoa has captured the initial OS thread for processing Cocoa
// events in runApp, it starts loop on another goroutine. It is locked
// to an OS thread for its OpenGL context.
//
// Two Cocoa threads deliver draw signals to loop. The primary source of
// draw events is the CVDisplayLink timer, which is tied to the display
// vsync. Secondary draw events come from [NSView drawRect:] when the
// window is resized.
func loop(ctx C.GLintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(ctx)

	for range draw {
		eventsIn <- paint.Event{}
	loop1:
		for {
			select {
			case <-gl.WorkAvailable:
				gl.DoWork()
			case <-endPaint:
				C.CGLFlushDrawable(C.CGLGetCurrentContext())
				break loop1
			}
		}
		drawDone <- struct{}{}
	}
}
Example #6
0
// drawLoop is the primary drawing loop.
//
// After Cocoa has created an NSWindow on the initial OS thread for
// processing Cocoa events in doNewWindow, it starts drawLoop on another
// goroutine. It is locked to an OS thread for its OpenGL context.
//
// Two Cocoa threads deliver draw signals to drawLoop. The primary
// source of draw events is the CVDisplayLink timer, which is tied to
// the display vsync. Secondary draw events come from [NSView drawRect:]
// when the window is resized.
func drawLoop(w *windowImpl) {
	runtime.LockOSThread()
	// TODO(crawshaw): there are several problematic issues around having
	// a draw loop per window, but resolving them requires some thought.
	// Firstly, nothing should race on gl.DoWork, so only one person can
	// do that at a time. Secondly, which GL ctx we use matters. A ctx
	// carries window-specific state (for example, the current glViewport
	// value), so we only want to run GL commands on the right context
	// between a <-w.draw and a <-w.drawDone. Thirdly, some GL functions
	// can be legitimately called outside of a window draw cycle, for
	// example, gl.CreateTexture. It doesn't matter which GL ctx we use
	// for that, but we have to use a valid one. So if a window gets
	// closed, it's important we swap the default ctx. More work needed.
	//
	// Similarly, should each window have its own endPaint channel, or should
	// the single dedicated draw loop have a single dedicated channel?
	C.makeCurrentContext(C.uintptr_t(w.ctx))

	workAvailable := w.worker.WorkAvailable()

	// TODO(crawshaw): exit this goroutine on Release.
	for {
		select {
		case <-workAvailable:
			w.worker.DoWork()
		case <-w.draw:
			// TODO(crawshaw): don't send a paint.Event unconditionally. Only
			// send one if the window actually needs redrawing.
			w.Send(paint.Event{})
		loop:
			for {
				select {
				case <-workAvailable:
					w.worker.DoWork()
				case <-w.publish:
					C.CGLFlushDrawable(C.CGLGetCurrentContext())
					break loop
				}
			}
			w.drawDone <- struct{}{}
		}
	}
}
Example #7
0
// loop is the primary drawing loop.
//
// After Cocoa has captured the initial OS thread for processing Cocoa
// events in runApp, it starts loop on another goroutine. It is locked
// to an OS thread for its OpenGL context.
//
// Two Cocoa threads deliver draw signals to loop. The primary source of
// draw events is the CVDisplayLink timer, which is tied to the display
// vsync. Secondary draw events come from [NSView drawRect:] when the
// window is resized.
func loop(ctx C.GLintptr) {
	runtime.LockOSThread()
	C.makeCurrentContext(ctx)

	for {
		select {
		case <-gl.WorkAvailable:
			gl.DoWork()
		case <-draw:
		loop1:
			for {
				select {
				case <-gl.WorkAvailable:
					gl.DoWork()
				case <-publish:
					C.CGLFlushDrawable(C.CGLGetCurrentContext())
					publishResult <- PublishResult{}
					break loop1
				}
			}
			drawDone <- struct{}{}
		}
	}
}
Example #8
0
// drawLoop is the primary drawing loop.
//
// After Cocoa has created an NSWindow on the initial OS thread for
// processing Cocoa events in newWindow, it starts drawLoop on another
// goroutine. It is locked to an OS thread for its OpenGL context.
//
// Two Cocoa threads deliver draw signals to drawLoop. The primary
// source of draw events is the CVDisplayLink timer, which is tied to
// the display vsync. Secondary draw events come from [NSView drawRect:]
// when the window is resized.
func (w *windowImpl) drawLoop(ctx uintptr) {
	runtime.LockOSThread()
	// TODO(crawshaw): there are several problematic issues around having
	// a draw loop per window, but resolving them requires some thought.
	// Firstly, nothing should race on gl.DoWork, so only one person can
	// do that at a time. Secondly, which GL ctx we use matters. A ctx
	// carries window-specific state (for example, the current glViewport
	// value), so we only want to run GL commands on the right context
	// between a <-w.draw and a <-w.drawDone. Thirdly, some GL functions
	// can be legitimately called outside of a window draw cycle, for
	// example, gl.CreateTexture. It doesn't matter which GL ctx we use
	// for that, but we have to use a valid one. So if a window gets
	// closed, it's important we swap the default ctx. More work needed.
	C.makeCurrentContext(C.uintptr_t(ctx))

	// TODO(crawshaw): exit this goroutine on Release.
	for {
		select {
		case <-gl.WorkAvailable:
			gl.DoWork()
		case <-w.draw:
			w.Send(paint.Event{})
		loop:
			for {
				select {
				case <-gl.WorkAvailable:
					gl.DoWork()
				case <-w.endPaint:
					C.CGLFlushDrawable(C.CGLGetCurrentContext())
					break loop
				}
			}
			w.drawDone <- struct{}{}
		}
	}
}
Example #9
0
func (this *Window) _makeCurrentContext() {
	C.makeCurrentContext(this.mContext)
}