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>
This commit is contained in:
parent
0d468be861
commit
068a51c195
@ -21,8 +21,7 @@ void glGenVertexArrays(GLsizei n, GLuint* array);
|
||||
void glBindVertexArray(GLuint array);
|
||||
|
||||
void runApp(void);
|
||||
void lockContext(GLintptr);
|
||||
void unlockContext(GLintptr);
|
||||
void makeCurrentContext(GLintptr);
|
||||
double backingScaleFactor();
|
||||
uint64 threadID();
|
||||
|
||||
@ -71,17 +70,6 @@ func setGeom(pixelsPerPt float32, width, height int) {
|
||||
configSwap(callbacks)
|
||||
}
|
||||
|
||||
func initGL() {
|
||||
// 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)
|
||||
}
|
||||
|
||||
var initGLOnce sync.Once
|
||||
|
||||
var touchEvents struct {
|
||||
sync.Mutex
|
||||
pending []event.Touch
|
||||
@ -109,16 +97,25 @@ 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) {
|
||||
// The call to lockContext loads the OpenGL context into
|
||||
// thread-local storage for use by the underlying GL calls
|
||||
// done in the user's Draw function. We need to stay on
|
||||
// the same thread throughout Draw, so we LockOSThread.
|
||||
runtime.LockOSThread()
|
||||
C.lockContext(ctx)
|
||||
if !startedgl {
|
||||
startedgl = true
|
||||
go gl.Start(func() {
|
||||
C.makeCurrentContext(ctx)
|
||||
|
||||
initGLOnce.Do(initGL)
|
||||
// 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
|
||||
@ -140,11 +137,7 @@ func drawgl(ctx C.GLintptr) {
|
||||
cb.Draw()
|
||||
}
|
||||
}
|
||||
|
||||
C.unlockContext(ctx)
|
||||
|
||||
// This may unlock the original main thread, but that's OK,
|
||||
// because by the time it does the thread has already entered
|
||||
// C.runApp, which won't give the thread up.
|
||||
runtime.UnlockOSThread()
|
||||
gl.Do(func() {
|
||||
C.CGLFlushDrawable(C.CGLGetCurrentContext())
|
||||
})
|
||||
}
|
||||
|
@ -22,17 +22,9 @@ static CVReturn displayLinkDraw(CVDisplayLinkRef displayLink, const CVTimeStamp*
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
void lockContext(GLintptr context) {
|
||||
void makeCurrentContext(GLintptr context) {
|
||||
NSOpenGLContext* ctx = (NSOpenGLContext*)context;
|
||||
[ctx makeCurrentContext];
|
||||
CGLLockContext([ctx CGLContextObj]);
|
||||
}
|
||||
|
||||
void unlockContext(GLintptr context) {
|
||||
NSOpenGLContext* ctx = (NSOpenGLContext*)context;
|
||||
[ctx flushBuffer];
|
||||
CGLUnlockContext([ctx CGLContextObj]);
|
||||
|
||||
}
|
||||
|
||||
uint64 threadID() {
|
||||
|
@ -24,7 +24,6 @@ import "C"
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/mobile/event"
|
||||
@ -121,12 +120,8 @@ func setGeom(width, height int) {
|
||||
configSwap(cb)
|
||||
}
|
||||
|
||||
func initGL() {
|
||||
stateStart(cb)
|
||||
}
|
||||
|
||||
var cb []Callbacks
|
||||
var initGLOnce sync.Once
|
||||
var startedgl = false
|
||||
|
||||
// touchIDs is the current active touches. The position in the array
|
||||
// is the ID, the value is the UITouch* pointer value.
|
||||
@ -181,14 +176,13 @@ func sendTouch(touch uintptr, touchType int, x, y float32) {
|
||||
|
||||
//export drawgl
|
||||
func drawgl(ctx uintptr) {
|
||||
// The call to lockContext loads the OpenGL context into
|
||||
// thread-local storage for use by the underlying GL calls
|
||||
// done in the user's Draw function. We need to stay on
|
||||
// the same thread throughout Draw, so we LockOSThread.
|
||||
runtime.LockOSThread()
|
||||
C.setContext(unsafe.Pointer(ctx))
|
||||
|
||||
initGLOnce.Do(initGL)
|
||||
if !startedgl {
|
||||
startedgl = true
|
||||
go gl.Start(func() {
|
||||
C.setContext(unsafe.Pointer(ctx))
|
||||
})
|
||||
stateStart(cb)
|
||||
}
|
||||
|
||||
touchEvents.Lock()
|
||||
pending := touchEvents.pending
|
||||
@ -210,12 +204,4 @@ func drawgl(ctx uintptr) {
|
||||
c.Draw()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
//C.unlockContext(ctx)
|
||||
|
||||
// This may unlock the original main thread, but that's OK,
|
||||
// because by the time it does the thread has already entered
|
||||
// C.runApp, which won't give the thread up.
|
||||
runtime.UnlockOSThread()
|
||||
}
|
||||
|
@ -91,12 +91,14 @@ import (
|
||||
)
|
||||
|
||||
func windowDraw(callbacks []Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
|
||||
C.createEGLWindow(w)
|
||||
go gl.Start(func() {
|
||||
C.createEGLWindow(w)
|
||||
})
|
||||
|
||||
// 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)
|
||||
C.eglSwapBuffers(C.display, C.surface)
|
||||
gl.Do(func() { C.eglSwapBuffers(C.display, C.surface) })
|
||||
|
||||
if errv := gl.GetError(); errv != gl.NO_ERROR {
|
||||
log.Printf("GL initialization error: %s", errv)
|
||||
@ -121,6 +123,7 @@ func windowDraw(callbacks []Callbacks, w *C.ANativeWindow, queue *C.AInputQueue)
|
||||
configSwap(callbacks)
|
||||
case <-windowDestroyed:
|
||||
stateStop(callbacks)
|
||||
gl.Stop()
|
||||
return
|
||||
default:
|
||||
for _, cb := range callbacks {
|
||||
@ -128,7 +131,7 @@ func windowDraw(callbacks []Callbacks, w *C.ANativeWindow, queue *C.AInputQueue)
|
||||
cb.Draw()
|
||||
}
|
||||
}
|
||||
C.eglSwapBuffers(C.display, C.surface)
|
||||
gl.Do(func() { C.eglSwapBuffers(C.display, C.surface) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
gl/doc.go
23
gl/doc.go
@ -14,6 +14,10 @@ https://www.khronos.org/opengles/sdk/docs/man/
|
||||
One notable departure from the C API is the introduction of types
|
||||
to represent common uses of GLint: Texture, Surface, Buffer, etc.
|
||||
|
||||
Calls are not safe for concurrent use. However calls can be made from
|
||||
any goroutine, the gl package removes the notion of thread-local
|
||||
context.
|
||||
|
||||
A tracing version of the OpenGL bindings is behind the `gldebug` build
|
||||
tag. It acts as a simplified version of apitrace. Build your Go binary
|
||||
with
|
||||
@ -34,4 +38,23 @@ the build tag before deploying any binaries.
|
||||
*/
|
||||
package gl // import "golang.org/x/mobile/gl"
|
||||
|
||||
/*
|
||||
Implementation details.
|
||||
|
||||
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.
|
||||
|
||||
This implementation ensures any goroutine can make GL calls, but it does
|
||||
not make the GL interface safe for simultaneous use by multiple goroutines.
|
||||
For the purpose of analyzing this code for race conditions, picture two
|
||||
separate goroutines: one blocked on gl.Start, and another making calls to
|
||||
the gl package exported functions.
|
||||
*/
|
||||
|
||||
//go:generate go run gendebug.go -o gldebug.go
|
||||
|
@ -154,42 +154,49 @@ func main() {
|
||||
}
|
||||
fmt.Fprintf(buf, ") {\n")
|
||||
|
||||
// Insert a defer block for tracing.
|
||||
fmt.Fprintf(buf, "defer func() {\n")
|
||||
fmt.Fprintf(buf, "\terrstr := errDrain()\n")
|
||||
switch fn.Name.Name {
|
||||
case "GetUniformLocation", "GetAttribLocation":
|
||||
fmt.Fprintf(buf, "\tr0.name = name\n")
|
||||
}
|
||||
fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name)
|
||||
for i, p := range paramTypes {
|
||||
if i > 0 {
|
||||
fmt.Fprint(buf, ", ")
|
||||
// gl.GetError is used by errDrain, which will be made part of
|
||||
// all functions. So do not apply it to gl.GetError to avoid
|
||||
// infinite recursion.
|
||||
skip := fn.Name.Name == "GetError"
|
||||
|
||||
if !skip {
|
||||
// Insert a defer block for tracing.
|
||||
fmt.Fprintf(buf, "defer func() {\n")
|
||||
fmt.Fprintf(buf, "\terrstr := errDrain()\n")
|
||||
switch fn.Name.Name {
|
||||
case "GetUniformLocation", "GetAttribLocation":
|
||||
fmt.Fprintf(buf, "\tr0.name = name\n")
|
||||
}
|
||||
fmt.Fprint(buf, typePrinter(p))
|
||||
}
|
||||
fmt.Fprintf(buf, ") ")
|
||||
if len(resultTypes) > 1 {
|
||||
fmt.Fprint(buf, "(")
|
||||
}
|
||||
for i, r := range resultTypes {
|
||||
if i > 0 {
|
||||
fmt.Fprint(buf, ", ")
|
||||
fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name)
|
||||
for i, p := range paramTypes {
|
||||
if i > 0 {
|
||||
fmt.Fprint(buf, ", ")
|
||||
}
|
||||
fmt.Fprint(buf, typePrinter(p))
|
||||
}
|
||||
fmt.Fprint(buf, typePrinter(r))
|
||||
fmt.Fprintf(buf, ") ")
|
||||
if len(resultTypes) > 1 {
|
||||
fmt.Fprint(buf, "(")
|
||||
}
|
||||
for i, r := range resultTypes {
|
||||
if i > 0 {
|
||||
fmt.Fprint(buf, ", ")
|
||||
}
|
||||
fmt.Fprint(buf, typePrinter(r))
|
||||
}
|
||||
if len(resultTypes) > 1 {
|
||||
fmt.Fprint(buf, ") ")
|
||||
}
|
||||
fmt.Fprintf(buf, "%%v\"")
|
||||
for i, p := range paramTypes {
|
||||
fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i]))
|
||||
}
|
||||
for i, r := range resultTypes {
|
||||
fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i]))
|
||||
}
|
||||
fmt.Fprintf(buf, ", errstr)\n")
|
||||
fmt.Fprintf(buf, "}()\n")
|
||||
}
|
||||
if len(resultTypes) > 1 {
|
||||
fmt.Fprint(buf, ") ")
|
||||
}
|
||||
fmt.Fprintf(buf, "%%v\"")
|
||||
for i, p := range paramTypes {
|
||||
fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i]))
|
||||
}
|
||||
for i, r := range resultTypes {
|
||||
fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i]))
|
||||
}
|
||||
fmt.Fprintf(buf, ", errstr)\n")
|
||||
fmt.Fprintf(buf, "}()\n")
|
||||
|
||||
// Print original body of function.
|
||||
for _, s := range fn.Body.List {
|
||||
@ -226,31 +233,20 @@ const preamble = `// Copyright 2014 The Go Authors. All rights reserved.
|
||||
|
||||
package gl
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef os_linux
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
#ifdef os_ios
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#endif
|
||||
#ifdef os_darwin_amd64
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
*/
|
||||
// #include "work.h"
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func errDrain() string {
|
||||
var errs []Enum
|
||||
for {
|
||||
e := Enum(C.glGetError())
|
||||
e := GetError()
|
||||
if e == 0 {
|
||||
break
|
||||
}
|
||||
|
1159
gl/gldebug.go
1159
gl/gldebug.go
File diff suppressed because it is too large
Load Diff
@ -280,7 +280,7 @@ func (img *Image) Draw(topLeft, topRight, bottomLeft geom.Point, srcBounds image
|
||||
// which gives:
|
||||
// a00 = (2*qx2 - 2*px2) / 2 = qx2 - px2
|
||||
// and similarly for the other elements of a.
|
||||
glimage.mvp.WriteAffine(&f32.Affine{{
|
||||
writeAffine(glimage.mvp, &f32.Affine{{
|
||||
qx2 - px2,
|
||||
px2 - sx2,
|
||||
qx2 + sx2,
|
||||
@ -315,7 +315,7 @@ func (img *Image) Draw(topLeft, topRight, bottomLeft geom.Point, srcBounds image
|
||||
// a10 + 0 + a12 = qy = py
|
||||
// 0 + a01 + a02 = sx = px
|
||||
// 0 + a11 + a12 = sy
|
||||
glimage.uvp.WriteAffine(&f32.Affine{{
|
||||
writeAffine(glimage.uvp, &f32.Affine{{
|
||||
qx - px,
|
||||
0,
|
||||
px,
|
||||
|
@ -39,11 +39,16 @@ func TestImage(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ctxGL := createContext()
|
||||
defer ctxGL.destroy()
|
||||
|
||||
var ctxGL *contextGL
|
||||
go gl.Start(func() {
|
||||
ctxGL = createContext()
|
||||
})
|
||||
start()
|
||||
defer stop()
|
||||
defer func() {
|
||||
stop()
|
||||
gl.Stop()
|
||||
ctxGL.destroy()
|
||||
}()
|
||||
|
||||
const (
|
||||
pixW = 100
|
||||
@ -69,7 +74,12 @@ func TestImage(t *testing.T) {
|
||||
t.Fatalf("framebuffer create failed: %v", status)
|
||||
}
|
||||
|
||||
gl.ClearColor(0, 0, 1, 1) // blue
|
||||
allocs := testing.AllocsPerRun(100, func() {
|
||||
gl.ClearColor(0, 0, 1, 1) // blue
|
||||
})
|
||||
if allocs != 0 {
|
||||
t.Errorf("unexpected allocations from calling gl.ClearColor: %f", allocs)
|
||||
}
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
gl.Viewport(0, 0, pixW, pixH)
|
||||
|
||||
|
@ -8,6 +8,7 @@ package glutil // import "golang.org/x/mobile/gl/glutil"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/mobile/f32"
|
||||
"golang.org/x/mobile/gl"
|
||||
)
|
||||
|
||||
@ -56,3 +57,18 @@ func loadShader(shaderType gl.Enum, src string) (gl.Shader, error) {
|
||||
}
|
||||
return shader, nil
|
||||
}
|
||||
|
||||
// writeAffine writes the contents of an Affine to a 3x3 matrix GL uniform.
|
||||
func writeAffine(u gl.Uniform, a *f32.Affine) {
|
||||
var m [9]float32
|
||||
m[0*3+0] = a[0][0]
|
||||
m[0*3+1] = a[1][0]
|
||||
m[0*3+2] = 0
|
||||
m[1*3+0] = a[0][1]
|
||||
m[1*3+1] = a[1][1]
|
||||
m[1*3+2] = 0
|
||||
m[2*3+0] = a[0][2]
|
||||
m[2*3+1] = a[1][2]
|
||||
m[2*3+2] = 1
|
||||
gl.UniformMatrix3fv(u, m[:])
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
// 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 linux darwin
|
||||
|
||||
package gl
|
||||
|
||||
// This file contains GL Types and their methods that are independent of the
|
||||
// "gldebug" build tag.
|
||||
|
||||
/*
|
||||
#cgo darwin,amd64 LDFLAGS: -framework OpenGL
|
||||
#cgo darwin,arm LDFLAGS: -framework OpenGLES
|
||||
#cgo darwin,arm64 LDFLAGS: -framework OpenGLES
|
||||
#cgo linux LDFLAGS: -lGLESv2
|
||||
|
||||
#cgo darwin,amd64 CFLAGS: -Dos_darwin_amd64
|
||||
#cgo darwin,arm CFLAGS: -Dos_ios
|
||||
#cgo darwin,arm64 CFLAGS: -Dos_ios
|
||||
#cgo linux CFLAGS: -Dos_linux
|
||||
|
||||
#ifdef os_linux
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
#ifdef os_ios
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#endif
|
||||
#ifdef os_darwin_amd64
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
|
||||
void blendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { glBlendColor(r, g, b, a); }
|
||||
void clearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { glClearColor(r, g, b, a); }
|
||||
void clearDepthf(GLfloat d) { glClearDepthf(d); }
|
||||
void depthRangef(GLfloat n, GLfloat f) { glDepthRangef(n, f); }
|
||||
void sampleCoverage(GLfloat v, GLboolean invert) { glSampleCoverage(v, invert); }
|
||||
*/
|
||||
import "C"
|
||||
import "golang.org/x/mobile/f32"
|
||||
|
||||
// WriteAffine writes the contents of an Affine to a 3x3 matrix GL uniform.
|
||||
func (u Uniform) WriteAffine(a *f32.Affine) {
|
||||
var m [9]float32
|
||||
m[0*3+0] = a[0][0]
|
||||
m[0*3+1] = a[1][0]
|
||||
m[0*3+2] = 0
|
||||
m[1*3+0] = a[0][1]
|
||||
m[1*3+1] = a[1][1]
|
||||
m[1*3+2] = 0
|
||||
m[2*3+0] = a[0][2]
|
||||
m[2*3+1] = a[1][2]
|
||||
m[2*3+2] = 1
|
||||
UniformMatrix3fv(u, m[:])
|
||||
}
|
||||
|
||||
// WriteMat4 writes the contents of a 4x4 matrix to a GL uniform.
|
||||
func (u Uniform) WriteMat4(p *f32.Mat4) {
|
||||
var m [16]float32
|
||||
m[0*4+0] = p[0][0]
|
||||
m[0*4+1] = p[1][0]
|
||||
m[0*4+2] = p[2][0]
|
||||
m[0*4+3] = p[3][0]
|
||||
m[1*4+0] = p[0][1]
|
||||
m[1*4+1] = p[1][1]
|
||||
m[1*4+2] = p[2][1]
|
||||
m[1*4+3] = p[3][1]
|
||||
m[2*4+0] = p[0][2]
|
||||
m[2*4+1] = p[1][2]
|
||||
m[2*4+2] = p[2][2]
|
||||
m[2*4+3] = p[3][2]
|
||||
m[3*4+0] = p[0][3]
|
||||
m[3*4+1] = p[1][3]
|
||||
m[3*4+2] = p[2][3]
|
||||
m[3*4+3] = p[3][3]
|
||||
UniformMatrix4fv(u, m[:])
|
||||
}
|
||||
|
||||
// WriteVec4 writes the contents of a 4-element vector to a GL uniform.
|
||||
func (u Uniform) WriteVec4(v *f32.Vec4) {
|
||||
Uniform4f(u, v[0], v[1], v[2], v[3])
|
||||
}
|
||||
|
||||
func glBoolean(b bool) C.GLboolean {
|
||||
if b {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
}
|
||||
|
||||
// Desktop OpenGL and the ES 2/3 APIs have a very slight difference
|
||||
// that is imperceptible to C programmers: some function parameters
|
||||
// use the type Glclampf and some use GLfloat. These two types are
|
||||
// equivalent in size and bit layout (both are single-precision
|
||||
// floats), but it plays havoc with cgo. We adjust the types by using
|
||||
// C wrappers for the problematic functions.
|
||||
|
||||
func blendColor(r, g, b, a float32) {
|
||||
C.blendColor(C.GLfloat(r), C.GLfloat(g), C.GLfloat(b), C.GLfloat(a))
|
||||
}
|
||||
func clearColor(r, g, b, a float32) {
|
||||
C.clearColor(C.GLfloat(r), C.GLfloat(g), C.GLfloat(b), C.GLfloat(a))
|
||||
}
|
||||
func clearDepthf(d float32) { C.clearDepthf(C.GLfloat(d)) }
|
||||
func depthRangef(n, f float32) { C.depthRangef(C.GLfloat(n), C.GLfloat(f)) }
|
||||
func sampleCoverage(v float32, i bool) { C.sampleCoverage(C.GLfloat(v), glBoolean(i)) }
|
@ -10,20 +10,7 @@ package gl
|
||||
// Alternate versions of the types defined in types.go with extra
|
||||
// debugging information attached. For documentation, see types.go.
|
||||
|
||||
/*
|
||||
#cgo darwin LDFLAGS: -framework OpenGL
|
||||
#cgo linux LDFLAGS: -lGLESv2
|
||||
#cgo darwin CFLAGS: -DGOOS_darwin
|
||||
#cgo linux CFLAGS: -DGOOS_linux
|
||||
|
||||
#ifdef GOOS_linux
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
|
||||
#ifdef GOOS_darwin
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
*/
|
||||
// #include "work.h"
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
@ -63,15 +50,15 @@ type Uniform struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (v Attrib) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Enum) c() C.GLenum { return C.GLenum(v) }
|
||||
func (v Program) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Shader) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Buffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Framebuffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Renderbuffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Texture) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Uniform) c() C.GLint { return C.GLint(v.Value) }
|
||||
func (v Attrib) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Enum) c() C.uintptr_t { return C.uintptr_t(v) }
|
||||
func (v Program) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Shader) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Buffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Framebuffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Renderbuffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Texture) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Uniform) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
|
||||
func (v Attrib) String() string { return fmt.Sprintf("Attrib(%d:%s)", v.Value, v.name) }
|
||||
func (v Program) String() string { return fmt.Sprintf("Program(%d)", v.Value) }
|
||||
|
@ -7,17 +7,7 @@
|
||||
|
||||
package gl
|
||||
|
||||
/*
|
||||
#ifdef os_linux
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
#ifdef os_ios
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#endif
|
||||
#ifdef os_darwin_amd64
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
*/
|
||||
// #include "work.h"
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
@ -68,15 +58,15 @@ type Uniform struct {
|
||||
Value int32
|
||||
}
|
||||
|
||||
func (v Attrib) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Enum) c() C.GLenum { return C.GLenum(v) }
|
||||
func (v Program) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Shader) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Buffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Framebuffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Renderbuffer) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Texture) c() C.GLuint { return C.GLuint(v.Value) }
|
||||
func (v Uniform) c() C.GLint { return C.GLint(v.Value) }
|
||||
func (v Attrib) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Enum) c() C.uintptr_t { return C.uintptr_t(v) }
|
||||
func (v Program) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Shader) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Buffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Framebuffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Renderbuffer) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Texture) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
func (v Uniform) c() C.uintptr_t { return C.uintptr_t(v.Value) }
|
||||
|
||||
func (v Attrib) String() string { return fmt.Sprintf("Attrib(%d)", v.Value) }
|
||||
func (v Program) String() string { return fmt.Sprintf("Program(%d)", v.Value) }
|
||||
|
479
gl/work.c
Normal file
479
gl/work.c
Normal file
@ -0,0 +1,479 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "_cgo_export.h"
|
||||
#include "work.h"
|
||||
|
||||
void processFn(struct fnargs* args) {
|
||||
switch (args->fn) {
|
||||
case glfnUNDEFINED:
|
||||
abort(); // bad glfn
|
||||
break;
|
||||
case glfnStop:
|
||||
abort(); // should never make it into C
|
||||
break;
|
||||
case glfnActiveTexture:
|
||||
glActiveTexture((GLenum)args->a0);
|
||||
break;
|
||||
case glfnAttachShader:
|
||||
glAttachShader((GLint)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnBindAttribLocation:
|
||||
glBindAttribLocation((GLint)args->a0, (GLint)args->a1, (GLchar*)args->a2);
|
||||
free((void*)args->a2);
|
||||
break;
|
||||
case glfnBindBuffer:
|
||||
glBindBuffer((GLenum)args->a0, (GLuint)args->a1);
|
||||
break;
|
||||
case glfnBindFramebuffer:
|
||||
glBindFramebuffer((GLenum)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnBindRenderbuffer:
|
||||
glBindRenderbuffer((GLenum)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnBindTexture:
|
||||
glBindTexture((GLenum)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnBlendColor:
|
||||
glBlendColor(*(GLfloat*)&args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
|
||||
break;
|
||||
case glfnBlendEquation:
|
||||
glBlendEquation((GLenum)args->a0);
|
||||
break;
|
||||
case glfnBlendEquationSeparate:
|
||||
glBlendEquationSeparate((GLenum)args->a0, (GLenum)args->a1);
|
||||
break;
|
||||
case glfnBlendFunc:
|
||||
glBlendFunc((GLenum)args->a0, (GLenum)args->a1);
|
||||
break;
|
||||
case glfnBlendFuncSeparate:
|
||||
glBlendFuncSeparate((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2, (GLenum)args->a3);
|
||||
break;
|
||||
case glfnBufferData:
|
||||
glBufferData((GLenum)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2, (GLenum)args->a3);
|
||||
break;
|
||||
case glfnBufferSubData:
|
||||
glBufferSubData((GLenum)args->a0, (GLint)args->a1, (GLsizeiptr)args->a2, (GLvoid*)args->a3);
|
||||
break;
|
||||
case glfnCheckFramebufferStatus:
|
||||
ret = glCheckFramebufferStatus((GLenum)args->a0);
|
||||
break;
|
||||
case glfnClear:
|
||||
glClear((GLenum)args->a0);
|
||||
break;
|
||||
case glfnClearColor:
|
||||
glClearColor(*(GLfloat*)&args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
|
||||
break;
|
||||
case glfnClearDepthf:
|
||||
glClearDepthf(*(GLfloat*)&args->a0);
|
||||
break;
|
||||
case glfnClearStencil:
|
||||
glClearStencil((GLint)args->a0);
|
||||
break;
|
||||
case glfnColorMask:
|
||||
glColorMask((GLboolean)args->a0, (GLboolean)args->a1, (GLboolean)args->a2, (GLboolean)args->a3);
|
||||
break;
|
||||
case glfnCompileShader:
|
||||
glCompileShader((GLint)args->a0);
|
||||
break;
|
||||
case glfnCompressedTexImage2D:
|
||||
glCompressedTexImage2D((GLenum)args->a0, (GLint)args->a1, (GLenum)args->a2, (GLint)args->a3, (GLint)args->a4, (GLint)args->a5, (GLsizeiptr)args->a6, (GLvoid*)args->a7);
|
||||
break;
|
||||
case glfnCompressedTexSubImage2D:
|
||||
glCompressedTexSubImage2D((GLenum)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3, (GLint)args->a4, (GLint)args->a5, (GLenum)args->a6, (GLsizeiptr)args->a7, (GLvoid*)args->a8);
|
||||
break;
|
||||
case glfnCopyTexImage2D:
|
||||
glCopyTexImage2D((GLenum)args->a0, (GLint)args->a1, (GLenum)args->a2, (GLint)args->a3, (GLint)args->a4, (GLint)args->a5, (GLint)args->a6, (GLint)args->a7);
|
||||
break;
|
||||
case glfnCopyTexSubImage2D:
|
||||
glCopyTexSubImage2D((GLenum)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3, (GLint)args->a4, (GLint)args->a5, (GLint)args->a6, (GLint)args->a7);
|
||||
break;
|
||||
case glfnCreateProgram:
|
||||
ret = glCreateProgram();
|
||||
break;
|
||||
case glfnCreateShader:
|
||||
ret = glCreateShader((GLenum)args->a0);
|
||||
break;
|
||||
case glfnCullFace:
|
||||
glCullFace((GLenum)args->a0);
|
||||
break;
|
||||
case glfnDeleteBuffer:
|
||||
glDeleteBuffers(1, (const GLuint*)(&args->a0));
|
||||
break;
|
||||
case glfnDeleteFramebuffer:
|
||||
glDeleteFramebuffers(1, (const GLuint*)(&args->a0));
|
||||
break;
|
||||
case glfnDeleteProgram:
|
||||
glDeleteProgram((GLint)args->a0);
|
||||
break;
|
||||
case glfnDeleteRenderbuffer:
|
||||
glDeleteRenderbuffers(1, (const GLuint*)(&args->a0));
|
||||
break;
|
||||
case glfnDeleteShader:
|
||||
glDeleteShader((GLint)args->a0);
|
||||
break;
|
||||
case glfnDeleteTexture:
|
||||
glDeleteTextures(1, (const GLuint*)(&args->a0));
|
||||
break;
|
||||
case glfnDepthFunc:
|
||||
glDepthFunc((GLenum)args->a0);
|
||||
break;
|
||||
case glfnDepthMask:
|
||||
glDepthMask((GLboolean)args->a0);
|
||||
break;
|
||||
case glfnDepthRangef:
|
||||
glDepthRangef(*(GLfloat*)&args->a0, *(GLfloat*)&args->a1);
|
||||
break;
|
||||
case glfnDetachShader:
|
||||
glDetachShader((GLint)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnDisable:
|
||||
glDisable((GLenum)args->a0);
|
||||
break;
|
||||
case glfnDisableVertexAttribArray:
|
||||
glDisableVertexAttribArray((GLint)args->a0);
|
||||
break;
|
||||
case glfnDrawArrays:
|
||||
glDrawArrays((GLenum)args->a0, (GLint)args->a1, (GLint)args->a2);
|
||||
break;
|
||||
case glfnDrawElements:
|
||||
glDrawElements((GLenum)args->a0, (GLint)args->a1, (GLenum)args->a2, (void*)args->a3);
|
||||
break;
|
||||
case glfnEnable:
|
||||
glEnable((GLenum)args->a0);
|
||||
break;
|
||||
case glfnEnableVertexAttribArray:
|
||||
glEnableVertexAttribArray((GLint)args->a0);
|
||||
break;
|
||||
case glfnFinish:
|
||||
glFinish();
|
||||
break;
|
||||
case glfnFlush:
|
||||
glFlush();
|
||||
break;
|
||||
case glfnFramebufferRenderbuffer:
|
||||
glFramebufferRenderbuffer((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2, (GLint)args->a3);
|
||||
break;
|
||||
case glfnFramebufferTexture2D:
|
||||
glFramebufferTexture2D((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2, (GLint)args->a3, (GLint)args->a4);
|
||||
break;
|
||||
case glfnFrontFace:
|
||||
glFrontFace((GLenum)args->a0);
|
||||
break;
|
||||
case glfnGenBuffer:
|
||||
glGenBuffers(1, (GLuint*)&ret);
|
||||
break;
|
||||
case glfnGenFramebuffer:
|
||||
glGenFramebuffers(1, (GLuint*)&ret);
|
||||
break;
|
||||
case glfnGenRenderbuffer:
|
||||
glGenRenderbuffers(1, (GLuint*)&ret);
|
||||
break;
|
||||
case glfnGenTexture:
|
||||
glGenTextures(1, (GLuint*)&ret);
|
||||
break;
|
||||
case glfnGenerateMipmap:
|
||||
glGenerateMipmap((GLenum)args->a0);
|
||||
break;
|
||||
case glfnGetActiveAttrib:
|
||||
glGetActiveAttrib(
|
||||
(GLuint)args->a0,
|
||||
(GLuint)args->a1,
|
||||
(GLsizei)args->a2,
|
||||
NULL,
|
||||
(GLint*)args->a4,
|
||||
(GLenum*)args->a5,
|
||||
(GLchar*)args->a6);
|
||||
break;
|
||||
case glfnGetActiveUniform:
|
||||
glGetActiveUniform(
|
||||
(GLuint)args->a0,
|
||||
(GLuint)args->a1,
|
||||
(GLsizei)args->a2,
|
||||
NULL,
|
||||
(GLint*)args->a4,
|
||||
(GLenum*)args->a5,
|
||||
(GLchar*)args->a6);
|
||||
break;
|
||||
case glfnGetAttachedShaders:
|
||||
glGetAttachedShaders((GLuint)args->a0, (GLsizei)args->a1, (GLsizei*)args->a2, (GLuint*)args->a3);
|
||||
break;
|
||||
case glfnGetAttribLocation:
|
||||
ret = glGetAttribLocation((GLint)args->a0, (GLchar*)args->a1);
|
||||
free((void*)args->a1);
|
||||
break;
|
||||
case glfnGetBooleanv:
|
||||
glGetBooleanv((GLenum)args->a0, (GLboolean*)args->a1);
|
||||
break;
|
||||
case glfnGetBufferParameteri:
|
||||
glGetBufferParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)&ret);
|
||||
break;
|
||||
case glfnGetFloatv:
|
||||
glGetFloatv((GLenum)args->a0, (GLfloat*)args->a1);
|
||||
break;
|
||||
case glfnGetIntegerv:
|
||||
glGetIntegerv((GLenum)args->a0, (GLint*)args->a1);
|
||||
break;
|
||||
case glfnGetError:
|
||||
ret = glGetError();
|
||||
break;
|
||||
case glfnGetFramebufferAttachmentParameteriv:
|
||||
glGetFramebufferAttachmentParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2, (GLint*)&ret);
|
||||
break;
|
||||
case glfnGetProgramiv:
|
||||
glGetProgramiv((GLint)args->a0, (GLenum)args->a1, (GLint*)&ret);
|
||||
break;
|
||||
case glfnGetProgramInfoLog:
|
||||
glGetProgramInfoLog((GLuint)args->a0, (GLsizei)args->a1, (GLsizei*)args->a2, (GLchar*)args->a3);
|
||||
break;
|
||||
case glfnGetRenderbufferParameteriv:
|
||||
glGetRenderbufferParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)&ret);
|
||||
break;
|
||||
case glfnGetShaderiv:
|
||||
glGetShaderiv((GLint)args->a0, (GLenum)args->a1, (GLint*)&ret);
|
||||
break;
|
||||
case glfnGetShaderInfoLog:
|
||||
glGetShaderInfoLog((GLuint)args->a0, (GLsizei)args->a1, (GLsizei*)args->a2, (GLchar*)args->a3);
|
||||
break;
|
||||
case glfnGetShaderPrecisionFormat:
|
||||
glGetShaderPrecisionFormat((GLenum)args->a0, (GLenum)args->a1, (GLint*)args->a2, (GLint*)args->a3);
|
||||
break;
|
||||
case glfnGetShaderSource:
|
||||
glGetShaderSource((GLuint)args->a0, (GLsizei)args->a1, (GLsizei*)args->a2, (GLchar*)args->a3);
|
||||
break;
|
||||
case glfnGetString:
|
||||
ret = (uintptr_t)glGetString((GLenum)args->a0);
|
||||
break;
|
||||
case glfnGetTexParameterfv:
|
||||
glGetTexParameterfv((GLenum)args->a0, (GLenum)args->a1, (GLfloat*)args->a2);
|
||||
break;
|
||||
case glfnGetTexParameteriv:
|
||||
glGetTexParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)args->a2);
|
||||
break;
|
||||
case glfnGetUniformfv:
|
||||
glGetUniformfv((GLuint)args->a0, (GLint)args->a1, (GLfloat*)args->a2);
|
||||
break;
|
||||
case glfnGetUniformiv:
|
||||
glGetUniformiv((GLuint)args->a0, (GLint)args->a1, (GLint*)args->a2);
|
||||
break;
|
||||
case glfnGetUniformLocation:
|
||||
ret = glGetUniformLocation((GLint)args->a0, (GLchar*)args->a1);
|
||||
free((void*)args->a1);
|
||||
break;
|
||||
case glfnGetVertexAttribfv:
|
||||
glGetVertexAttribfv((GLuint)args->a0, (GLenum)args->a1, (GLfloat*)args->a2);
|
||||
break;
|
||||
case glfnGetVertexAttribiv:
|
||||
glGetVertexAttribiv((GLuint)args->a0, (GLenum)args->a1, (GLint*)args->a2);
|
||||
break;
|
||||
case glfnHint:
|
||||
glHint((GLenum)args->a0, (GLenum)args->a1);
|
||||
break;
|
||||
case glfnIsBuffer:
|
||||
ret = glIsBuffer((GLint)args->a0);
|
||||
break;
|
||||
case glfnIsEnabled:
|
||||
ret = glIsEnabled((GLenum)args->a0);
|
||||
break;
|
||||
case glfnIsFramebuffer:
|
||||
ret = glIsFramebuffer((GLint)args->a0);
|
||||
break;
|
||||
case glfnIsProgram:
|
||||
ret = glIsProgram((GLint)args->a0);
|
||||
break;
|
||||
case glfnIsRenderbuffer:
|
||||
ret = glIsRenderbuffer((GLint)args->a0);
|
||||
break;
|
||||
case glfnIsShader:
|
||||
ret = glIsShader((GLint)args->a0);
|
||||
break;
|
||||
case glfnIsTexture:
|
||||
ret = glIsTexture((GLint)args->a0);
|
||||
break;
|
||||
case glfnLineWidth:
|
||||
glLineWidth(*(GLfloat*)&args->a0);
|
||||
break;
|
||||
case glfnLinkProgram:
|
||||
glLinkProgram((GLint)args->a0);
|
||||
break;
|
||||
case glfnPixelStorei:
|
||||
glPixelStorei((GLenum)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnPolygonOffset:
|
||||
glPolygonOffset(*(GLfloat*)&args->a0, *(GLfloat*)&args->a1);
|
||||
break;
|
||||
case glfnReadPixels:
|
||||
glReadPixels((GLint)args->a0, (GLint)args->a1, (GLsizei)args->a2, (GLsizei)args->a3, (GLenum)args->a4, (GLenum)args->a5, (void*)args->a6);
|
||||
break;
|
||||
case glfnReleaseShaderCompiler:
|
||||
glReleaseShaderCompiler();
|
||||
break;
|
||||
case glfnRenderbufferStorage:
|
||||
glRenderbufferStorage((GLenum)args->a0, (GLenum)args->a1, (GLint)args->a2, (GLint)args->a3);
|
||||
break;
|
||||
case glfnSampleCoverage:
|
||||
glSampleCoverage(*(GLfloat*)&args->a0, (GLboolean)args->a1);
|
||||
break;
|
||||
case glfnScissor:
|
||||
glScissor((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3);
|
||||
break;
|
||||
case glfnShaderSource:
|
||||
#if defined(os_ios) || defined(os_osx)
|
||||
glShaderSource((GLuint)args->a0, (GLsizei)args->a1, (const GLchar *const *)args->a2, NULL);
|
||||
#else
|
||||
glShaderSource((GLuint)args->a0, (GLsizei)args->a1, (const GLchar **)args->a2, NULL);
|
||||
#endif
|
||||
free(*(void**)args->a2);
|
||||
free((void*)args->a2);
|
||||
break;
|
||||
case glfnStencilFunc:
|
||||
glStencilFunc((GLenum)args->a0, (GLint)args->a1, (GLuint)args->a2);
|
||||
break;
|
||||
case glfnStencilFuncSeparate:
|
||||
glStencilFuncSeparate((GLenum)args->a0, (GLenum)args->a1, (GLint)args->a2, (GLuint)args->a3);
|
||||
break;
|
||||
case glfnStencilMask:
|
||||
glStencilMask((GLuint)args->a0);
|
||||
break;
|
||||
case glfnStencilMaskSeparate:
|
||||
glStencilMaskSeparate((GLenum)args->a0, (GLuint)args->a1);
|
||||
break;
|
||||
case glfnStencilOp:
|
||||
glStencilOp((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2);
|
||||
break;
|
||||
case glfnStencilOpSeparate:
|
||||
glStencilOpSeparate((GLenum)args->a0, (GLenum)args->a1, (GLenum)args->a2, (GLenum)args->a3);
|
||||
break;
|
||||
case glfnTexImage2D:
|
||||
glTexImage2D(
|
||||
(GLenum)args->a0,
|
||||
(GLint)args->a1,
|
||||
(GLint)args->a2,
|
||||
(GLsizei)args->a3,
|
||||
(GLsizei)args->a4,
|
||||
0, // border
|
||||
(GLenum)args->a5,
|
||||
(GLenum)args->a6,
|
||||
(const GLvoid*)args->a7);
|
||||
break;
|
||||
case glfnTexSubImage2D:
|
||||
glTexSubImage2D(
|
||||
(GLenum)args->a0,
|
||||
(GLint)args->a1,
|
||||
(GLint)args->a2,
|
||||
(GLint)args->a3,
|
||||
(GLsizei)args->a4,
|
||||
(GLsizei)args->a5,
|
||||
(GLenum)args->a6,
|
||||
(GLenum)args->a7,
|
||||
(const GLvoid*)args->a8);
|
||||
break;
|
||||
case glfnTexParameterf:
|
||||
glTexParameterf((GLenum)args->a0, (GLenum)args->a1, *(GLfloat*)&args->a2);
|
||||
break;
|
||||
case glfnTexParameterfv:
|
||||
glTexParameterfv((GLenum)args->a0, (GLenum)args->a1, (GLfloat*)args->a2);
|
||||
break;
|
||||
case glfnTexParameteri:
|
||||
glTexParameteri((GLenum)args->a0, (GLenum)args->a1, (GLint)args->a2);
|
||||
break;
|
||||
case glfnTexParameteriv:
|
||||
glTexParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)args->a2);
|
||||
break;
|
||||
case glfnUniform1f:
|
||||
glUniform1f((GLint)args->a0, *(GLfloat*)&args->a1);
|
||||
break;
|
||||
case glfnUniform1fv:
|
||||
glUniform1fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform1i:
|
||||
glUniform1i((GLint)args->a0, (GLint)args->a1);
|
||||
break;
|
||||
case glfnUniform1iv:
|
||||
glUniform1iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform2f:
|
||||
glUniform2f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2);
|
||||
break;
|
||||
case glfnUniform2fv:
|
||||
glUniform2fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform2i:
|
||||
glUniform2i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2);
|
||||
break;
|
||||
case glfnUniform2iv:
|
||||
glUniform2iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform3f:
|
||||
glUniform3f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
|
||||
break;
|
||||
case glfnUniform3fv:
|
||||
glUniform3fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform3i:
|
||||
glUniform3i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3);
|
||||
break;
|
||||
case glfnUniform3iv:
|
||||
glUniform3iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform4f:
|
||||
glUniform4f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3, *(GLfloat*)&args->a4);
|
||||
break;
|
||||
case glfnUniform4fv:
|
||||
glUniform4fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniform4i:
|
||||
glUniform4i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3, (GLint)args->a4);
|
||||
break;
|
||||
case glfnUniform4iv:
|
||||
glUniform4iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniformMatrix2fv:
|
||||
glUniformMatrix2fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniformMatrix3fv:
|
||||
glUniformMatrix3fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUniformMatrix4fv:
|
||||
glUniformMatrix4fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)args->a2);
|
||||
break;
|
||||
case glfnUseProgram:
|
||||
glUseProgram((GLint)args->a0);
|
||||
break;
|
||||
case glfnValidateProgram:
|
||||
glValidateProgram((GLint)args->a0);
|
||||
break;
|
||||
case glfnVertexAttrib1f:
|
||||
glVertexAttrib1f((GLint)args->a0, *(GLfloat*)&args->a1);
|
||||
break;
|
||||
case glfnVertexAttrib1fv:
|
||||
glVertexAttrib1fv((GLint)args->a0, (GLfloat*)args->a1);
|
||||
break;
|
||||
case glfnVertexAttrib2f:
|
||||
glVertexAttrib2f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2);
|
||||
break;
|
||||
case glfnVertexAttrib2fv:
|
||||
glVertexAttrib2fv((GLint)args->a0, (GLfloat*)args->a1);
|
||||
break;
|
||||
case glfnVertexAttrib3f:
|
||||
glVertexAttrib3f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
|
||||
break;
|
||||
case glfnVertexAttrib3fv:
|
||||
glVertexAttrib3fv((GLint)args->a0, (GLfloat*)args->a1);
|
||||
break;
|
||||
case glfnVertexAttrib4f:
|
||||
glVertexAttrib4f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3, *(GLfloat*)&args->a4);
|
||||
break;
|
||||
case glfnVertexAttrib4fv:
|
||||
glVertexAttrib4fv((GLint)args->a0, (GLfloat*)args->a1);
|
||||
break;
|
||||
case glfnVertexAttribPointer:
|
||||
glVertexAttribPointer((GLuint)args->a0, (GLint)args->a1, (GLenum)args->a2, (GLboolean)args->a3, (GLsizei)args->a4, (const GLvoid*)args->a5);
|
||||
break;
|
||||
case glfnViewport:
|
||||
glViewport((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3);
|
||||
break;
|
||||
}
|
||||
}
|
130
gl/work.go
Normal file
130
gl/work.go
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
package gl
|
||||
|
||||
/*
|
||||
#cgo darwin,amd64 LDFLAGS: -framework OpenGL
|
||||
#cgo darwin,arm LDFLAGS: -framework OpenGLES
|
||||
#cgo darwin,arm64 LDFLAGS: -framework OpenGLES
|
||||
#cgo linux LDFLAGS: -lGLESv2
|
||||
|
||||
#cgo darwin,amd64 CFLAGS: -Dos_osx
|
||||
#cgo darwin,arm CFLAGS: -Dos_ios
|
||||
#cgo darwin,arm64 CFLAGS: -Dos_ios
|
||||
#cgo linux CFLAGS: -Dos_linux
|
||||
|
||||
#include <stdint.h>
|
||||
#include "work.h"
|
||||
|
||||
struct fnargs cargs[10];
|
||||
uintptr_t ret;
|
||||
|
||||
void process(int count) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
processFn(&cargs[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import "runtime"
|
||||
|
||||
// work is a queue of calls to execute.
|
||||
var work = make(chan call, 10)
|
||||
|
||||
// retvalue is sent a return value when blocking calls complete.
|
||||
// It is safe to use a global unbuffered channel here as calls
|
||||
// cannot currently be made concurrently.
|
||||
var retvalue = make(chan C.uintptr_t)
|
||||
|
||||
type call struct {
|
||||
blocking bool
|
||||
fn func()
|
||||
args C.struct_fnargs
|
||||
}
|
||||
|
||||
// Do calls fn on the OS thread with the GL context.
|
||||
func Do(fn func()) {
|
||||
work <- call{
|
||||
fn: fn,
|
||||
blocking: true,
|
||||
}
|
||||
<-retvalue
|
||||
}
|
||||
|
||||
// Stop stops the current GL processing.
|
||||
func Stop() {
|
||||
var call call
|
||||
call.blocking = true
|
||||
call.args.fn = C.glfnStop
|
||||
work <- call
|
||||
<-retvalue
|
||||
}
|
||||
|
||||
// Start executes GL functions on a fixed OS thread, starting with initCtx.
|
||||
// It blocks until Stop is called. Typical use:
|
||||
//
|
||||
// go gl.Start(func() {
|
||||
// // establish a GL context, using for example, EGL.
|
||||
// })
|
||||
//
|
||||
// // long running GL calls from any goroutine
|
||||
//
|
||||
// gl.Stop()
|
||||
func Start(initCtx func()) {
|
||||
runtime.LockOSThread()
|
||||
initCtx()
|
||||
|
||||
queue := make([]call, 0, len(work))
|
||||
for {
|
||||
// Wait until at least one piece of work is ready.
|
||||
// Accumulate work until a piece is marked as blocking.
|
||||
select {
|
||||
case w := <-work:
|
||||
queue = append(queue, w)
|
||||
}
|
||||
blocking := queue[len(queue)-1].blocking
|
||||
enqueue:
|
||||
for len(queue) < cap(queue) && !blocking {
|
||||
select {
|
||||
case w := <-work:
|
||||
queue = append(queue, w)
|
||||
blocking = queue[len(queue)-1].blocking
|
||||
default:
|
||||
break enqueue
|
||||
}
|
||||
}
|
||||
|
||||
// Process the queued GL functions.
|
||||
fn := queue[len(queue)-1].fn
|
||||
stop := queue[len(queue)-1].args.fn == C.glfnStop
|
||||
if fn != nil || stop {
|
||||
queue = queue[:len(queue)-1]
|
||||
}
|
||||
for i := range queue {
|
||||
C.cargs[i] = queue[i].args
|
||||
}
|
||||
C.process(C.int(len(queue)))
|
||||
if fn != nil {
|
||||
fn()
|
||||
}
|
||||
|
||||
// Cleanup and signal.
|
||||
queue = queue[:0]
|
||||
if blocking {
|
||||
retvalue <- C.ret
|
||||
}
|
||||
if stop {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func glBoolean(b bool) C.uintptr_t {
|
||||
if b {
|
||||
return TRUE
|
||||
}
|
||||
return FALSE
|
||||
}
|
180
gl/work.h
Normal file
180
gl/work.h
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#ifdef os_linux
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
#ifdef os_ios
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#endif
|
||||
#ifdef os_osx
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum {
|
||||
glfnUNDEFINED,
|
||||
glfnStop,
|
||||
|
||||
glfnActiveTexture,
|
||||
glfnAttachShader,
|
||||
glfnBindAttribLocation,
|
||||
glfnBindBuffer,
|
||||
glfnBindFramebuffer,
|
||||
glfnBindRenderbuffer,
|
||||
glfnBindTexture,
|
||||
glfnBlendColor,
|
||||
glfnBlendEquation,
|
||||
glfnBlendEquationSeparate,
|
||||
glfnBlendFunc,
|
||||
glfnBlendFuncSeparate,
|
||||
glfnBufferData,
|
||||
glfnBufferSubData,
|
||||
glfnCheckFramebufferStatus,
|
||||
glfnClear,
|
||||
glfnClearColor,
|
||||
glfnClearDepthf,
|
||||
glfnClearStencil,
|
||||
glfnColorMask,
|
||||
glfnCompileShader,
|
||||
glfnCompressedTexImage2D,
|
||||
glfnCompressedTexSubImage2D,
|
||||
glfnCopyTexImage2D,
|
||||
glfnCopyTexSubImage2D,
|
||||
glfnCreateProgram,
|
||||
glfnCreateShader,
|
||||
glfnCullFace,
|
||||
glfnDeleteBuffer,
|
||||
glfnDeleteFramebuffer,
|
||||
glfnDeleteProgram,
|
||||
glfnDeleteRenderbuffer,
|
||||
glfnDeleteShader,
|
||||
glfnDeleteTexture,
|
||||
glfnDepthFunc,
|
||||
glfnDepthRangef,
|
||||
glfnDepthMask,
|
||||
glfnDetachShader,
|
||||
glfnDisable,
|
||||
glfnDisableVertexAttribArray,
|
||||
glfnDrawArrays,
|
||||
glfnDrawElements,
|
||||
glfnEnable,
|
||||
glfnEnableVertexAttribArray,
|
||||
glfnFinish,
|
||||
glfnFlush,
|
||||
glfnFramebufferRenderbuffer,
|
||||
glfnFramebufferTexture2D,
|
||||
glfnFrontFace,
|
||||
glfnGenBuffer,
|
||||
glfnGenFramebuffer,
|
||||
glfnGenRenderbuffer,
|
||||
glfnGenTexture,
|
||||
glfnGenerateMipmap,
|
||||
glfnGetActiveAttrib,
|
||||
glfnGetActiveUniform,
|
||||
glfnGetAttachedShaders,
|
||||
glfnGetAttribLocation,
|
||||
glfnGetBooleanv,
|
||||
glfnGetBufferParameteri,
|
||||
glfnGetError,
|
||||
glfnGetFloatv,
|
||||
glfnGetFramebufferAttachmentParameteriv,
|
||||
glfnGetIntegerv,
|
||||
glfnGetProgramInfoLog,
|
||||
glfnGetProgramiv,
|
||||
glfnGetRenderbufferParameteriv,
|
||||
glfnGetShaderInfoLog,
|
||||
glfnGetShaderPrecisionFormat,
|
||||
glfnGetShaderSource,
|
||||
glfnGetShaderiv,
|
||||
glfnGetString,
|
||||
glfnGetTexParameterfv,
|
||||
glfnGetTexParameteriv,
|
||||
glfnGetUniformLocation,
|
||||
glfnGetUniformfv,
|
||||
glfnGetUniformiv,
|
||||
glfnGetVertexAttribfv,
|
||||
glfnGetVertexAttribiv,
|
||||
glfnHint,
|
||||
glfnIsBuffer,
|
||||
glfnIsEnabled,
|
||||
glfnIsFramebuffer,
|
||||
glfnIsProgram,
|
||||
glfnIsRenderbuffer,
|
||||
glfnIsShader,
|
||||
glfnIsTexture,
|
||||
glfnLineWidth,
|
||||
glfnLinkProgram,
|
||||
glfnPixelStorei,
|
||||
glfnPolygonOffset,
|
||||
glfnReadPixels,
|
||||
glfnReleaseShaderCompiler,
|
||||
glfnRenderbufferStorage,
|
||||
glfnSampleCoverage,
|
||||
glfnScissor,
|
||||
glfnShaderSource,
|
||||
glfnStencilFunc,
|
||||
glfnStencilFuncSeparate,
|
||||
glfnStencilMask,
|
||||
glfnStencilMaskSeparate,
|
||||
glfnStencilOp,
|
||||
glfnStencilOpSeparate,
|
||||
glfnTexImage2D,
|
||||
glfnTexParameterf,
|
||||
glfnTexParameterfv,
|
||||
glfnTexParameteri,
|
||||
glfnTexParameteriv,
|
||||
glfnTexSubImage2D,
|
||||
glfnUniform1f,
|
||||
glfnUniform1fv,
|
||||
glfnUniform1i,
|
||||
glfnUniform1iv,
|
||||
glfnUniform2f,
|
||||
glfnUniform2fv,
|
||||
glfnUniform2i,
|
||||
glfnUniform2iv,
|
||||
glfnUniform3f,
|
||||
glfnUniform3fv,
|
||||
glfnUniform3i,
|
||||
glfnUniform3iv,
|
||||
glfnUniform4f,
|
||||
glfnUniform4fv,
|
||||
glfnUniform4i,
|
||||
glfnUniform4iv,
|
||||
glfnUniformMatrix2fv,
|
||||
glfnUniformMatrix3fv,
|
||||
glfnUniformMatrix4fv,
|
||||
glfnUseProgram,
|
||||
glfnValidateProgram,
|
||||
glfnVertexAttrib1f,
|
||||
glfnVertexAttrib1fv,
|
||||
glfnVertexAttrib2f,
|
||||
glfnVertexAttrib2fv,
|
||||
glfnVertexAttrib3f,
|
||||
glfnVertexAttrib3fv,
|
||||
glfnVertexAttrib4f,
|
||||
glfnVertexAttrib4fv,
|
||||
glfnVertexAttribPointer,
|
||||
glfnViewport,
|
||||
} glfn;
|
||||
|
||||
struct fnargs {
|
||||
glfn fn;
|
||||
|
||||
uintptr_t a0;
|
||||
uintptr_t a1;
|
||||
uintptr_t a2;
|
||||
uintptr_t a3;
|
||||
uintptr_t a4;
|
||||
uintptr_t a5;
|
||||
uintptr_t a6;
|
||||
uintptr_t a7;
|
||||
uintptr_t a8;
|
||||
};
|
||||
|
||||
extern uintptr_t ret;
|
||||
|
||||
extern void processFn(struct fnargs* args);
|
Loading…
x
Reference in New Issue
Block a user