2
0
mirror of synced 2025-02-23 23:08:14 +00:00
mobile/app/darwin_amd64.go
David Crawshaw 068a51c195 gl: batch calls onto a dedicated context thread
All GL function calls fill out a C.struct_fnargs and drop it on the
work queue. The Start function drains the work queue and hands
over a batch of calls to C.process which runs them. This allows
multiple GL calls to be executed in a single cgo call.

A GL call is marked as blocking if it returns a value, or if it
takes a Go pointer. In this case the call will not return until
C.process sends a value on the retvalue channel.

Change-Id: I4c76b2a8ad55f57b0c98d200d0fb708d4634e042
Reviewed-on: https://go-review.googlesource.com/10452
Reviewed-by: Nigel Tao <nigeltao@golang.org>
2015-06-01 15:35:03 +00:00

144 lines
3.4 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package app
// Simple on-screen app debugging for OS X. Not an officially supported
// development target for apps, as screens with mice are very different
// than screens with touch panels.
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl.h>
#include <pthread.h>
void glGenVertexArrays(GLsizei n, GLuint* array);
void glBindVertexArray(GLuint array);
void runApp(void);
void makeCurrentContext(GLintptr);
double backingScaleFactor();
uint64 threadID();
*/
import "C"
import (
"log"
"runtime"
"sync"
"golang.org/x/mobile/event"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
var initThreadID uint64
func init() {
// Lock the goroutine responsible for initialization to an OS thread.
// This means the goroutine running main (and calling the run function
// below) is locked to the OS thread that started the program. This is
// necessary for the correct delivery of Cocoa events to the process.
//
// A discussion on this topic:
// https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ
runtime.LockOSThread()
initThreadID = uint64(C.threadID())
}
func run(callbacks []Callbacks) {
if tid := uint64(C.threadID()); tid != initThreadID {
log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID)
}
close(mainCalled)
C.runApp()
}
//export setGeom
func setGeom(pixelsPerPt float32, width, height int) {
if geom.PixelsPerPt == 0 {
// Macs default to 72 DPI, so scales are equivalent.
geom.PixelsPerPt = pixelsPerPt
}
configAlt.Width = geom.Pt(float32(width) / geom.PixelsPerPt)
configAlt.Height = geom.Pt(float32(height) / geom.PixelsPerPt)
configSwap(callbacks)
}
var touchEvents struct {
sync.Mutex
pending []event.Touch
}
func sendTouch(ty event.TouchType, x, y float32) {
touchEvents.Lock()
touchEvents.pending = append(touchEvents.pending, event.Touch{
ID: 0,
Type: ty,
Loc: geom.Point{
X: geom.Pt(x / geom.PixelsPerPt),
Y: GetConfig().Height - geom.Pt(y/geom.PixelsPerPt),
},
})
touchEvents.Unlock()
}
//export eventMouseDown
func eventMouseDown(x, y float32) { sendTouch(event.TouchStart, x, y) }
//export eventMouseDragged
func eventMouseDragged(x, y float32) { sendTouch(event.TouchMove, x, y) }
//export eventMouseEnd
func eventMouseEnd(x, y float32) { sendTouch(event.TouchEnd, x, y) }
var startedgl = false
//export drawgl
func drawgl(ctx C.GLintptr) {
if !startedgl {
startedgl = true
go gl.Start(func() {
C.makeCurrentContext(ctx)
// 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.
var id C.GLuint
C.glGenVertexArrays(1, &id)
C.glBindVertexArray(id)
})
stateStart(callbacks)
}
touchEvents.Lock()
pending := touchEvents.pending
touchEvents.pending = nil
touchEvents.Unlock()
for _, cb := range callbacks {
if cb.Touch != nil {
for _, e := range pending {
cb.Touch(e)
}
}
}
// TODO: is the library or the app responsible for clearing the buffers?
gl.ClearColor(0, 0, 0, 1)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
for _, cb := range callbacks {
if cb.Draw != nil {
cb.Draw()
}
}
gl.Do(func() {
C.CGLFlushDrawable(C.CGLGetCurrentContext())
})
}