app: remove OS X display link timer

The CGL display link is a timer keyed on screen refresh rate. It made
sense to use it when the app package controlled the screen paint
cycle. Now that the paint cycle control has moved to the user, and
given that we have always made the equivalent of Publish block until
vsync, it is just complicating matters. The user can come up with
their own timer, and safely dedicate a goroutine to event handling
that paints as fast as it likes without running over the vsync time.

A version of this for iOS will follow (giving up on the timer provided
by GLKViewController) when I get my iOS setup working again.

(Note there is also a bug in the way drawgl works presently. This CL
doesn't fix the bug, but is a first step in untangling the draw loop
so I can fix it.)

Change-Id: I464d5b15f018527d98b792026fb3899681f24e4b
Reviewed-on: https://go-review.googlesource.com/15470
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw 2015-10-06 15:33:51 -04:00
parent cc7d486c7d
commit 0d45604e75
2 changed files with 25 additions and 43 deletions

View File

@ -12,7 +12,7 @@ package app
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore
#cgo LDFLAGS: -framework Cocoa -framework OpenGL
#import <Carbon/Carbon.h> // for HIToolbox/Events.h
#import <Cocoa/Cocoa.h>
#include <pthread.h>
@ -70,45 +70,52 @@ func main(f func(App)) {
// 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.
// 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 <-draw:
case <-theApp.publish:
loop1:
for {
select {
case <-workAvailable:
a.worker.DoWork()
case <-theApp.publish:
C.CGLFlushDrawable(C.CGLGetCurrentContext())
theApp.publishResult <- PublishResult{}
default:
break loop1
}
}
drawDone <- struct{}{}
C.CGLFlushDrawable(C.CGLGetCurrentContext())
theApp.publishResult <- PublishResult{}
select {
case drawDone <- struct{}{}:
default:
}
}
}
}
var (
draw = make(chan struct{})
drawDone = make(chan struct{})
)
var drawDone = make(chan struct{})
// drawgl is used by Cocoa to occasionally request screen updates.
//
//export drawgl
func drawgl() {
draw <- struct{}{}
<-drawDone
switch theApp.lifecycleStage {
case lifecycle.StageFocused, lifecycle.StageVisible:
theApp.Send(paint.Event{})
<-drawDone
}
}
//export startloop

View File

@ -11,14 +11,6 @@
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#import <OpenGL/gl3.h>
#import <QuartzCore/CVReturn.h>
#import <QuartzCore/CVBase.h>
static CVReturn displayLinkDraw(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
drawgl();
return kCVReturnSuccess;
}
void makeCurrentContext(GLintptr context) {
NSOpenGLContext* ctx = (NSOpenGLContext*)context;
@ -33,10 +25,8 @@ uint64 threadID() {
return id;
}
@interface MobileGLView : NSOpenGLView<NSApplicationDelegate, NSWindowDelegate>
{
CVDisplayLinkRef displayLink;
}
@end
@ -46,13 +36,6 @@ uint64 threadID() {
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
CVDisplayLinkSetOutputCallback(displayLink, &displayLinkDraw, self);
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
// Using attribute arrays in OpenGL 3.3 requires the use of a VBA.
// But VBAs don't exist in ES 2. So we bind a default one.
GLuint vba;
@ -96,11 +79,8 @@ uint64 threadID() {
}
- (void)drawRect:(NSRect)theRect {
// Called during resize. Do an extra draw if we are visible.
// This gets rid of flicker when resizing.
if (CVDisplayLinkIsRunning(displayLink)) {
drawgl();
}
// Called during resize. This gets rid of flicker when resizing.
drawgl();
}
- (void)mouseDown:(NSEvent *)theEvent {
@ -136,7 +116,6 @@ uint64 threadID() {
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
[self.window makeKeyAndOrderFront:self];
lifecycleVisible();
CVDisplayLinkStart(displayLink);
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
@ -144,17 +123,14 @@ uint64 threadID() {
}
- (void)applicationDidHide:(NSNotification *)aNotification {
CVDisplayLinkStop(displayLink);
lifecycleAlive();
}
- (void)applicationWillUnhide:(NSNotification *)notification {
lifecycleVisible();
CVDisplayLinkStart(displayLink);
}
- (void)windowWillClose:(NSNotification *)notification {
CVDisplayLinkStop(displayLink);
lifecycleAlive();
}
@end
@ -204,7 +180,6 @@ uint64 threadID() {
}
@end
void
runApp(void) {
[NSAutoreleasePool new];