github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/gl/work.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin linux 6 7 package gl 8 9 /* 10 #cgo darwin,amd64 LDFLAGS: -framework OpenGL 11 #cgo darwin,arm LDFLAGS: -framework OpenGLES 12 #cgo darwin,arm64 LDFLAGS: -framework OpenGLES 13 #cgo linux LDFLAGS: -lGLESv2 14 15 #cgo darwin,amd64 CFLAGS: -Dos_osx 16 #cgo darwin,arm CFLAGS: -Dos_ios 17 #cgo darwin,arm64 CFLAGS: -Dos_ios 18 #cgo linux CFLAGS: -Dos_linux 19 20 #include <stdint.h> 21 #include "work.h" 22 23 uintptr_t process(struct fnargs* cargs, char* parg0, char* parg1, char* parg2, int count) { 24 uintptr_t ret; 25 26 ret = processFn(&cargs[0], parg0); 27 if (count > 1) { 28 ret = processFn(&cargs[1], parg1); 29 } 30 if (count > 2) { 31 ret = processFn(&cargs[2], parg2); 32 } 33 34 return ret; 35 } 36 */ 37 import "C" 38 39 import "unsafe" 40 41 const workbufLen = 3 42 43 type context struct { 44 cptr uintptr 45 debug int32 46 47 workAvailable chan struct{} 48 49 // work is a queue of calls to execute. 50 work chan call 51 52 // retvalue is sent a return value when blocking calls complete. 53 // It is safe to use a global unbuffered channel here as calls 54 // cannot currently be made concurrently. 55 // 56 // TODO: the comment above about concurrent calls isn't actually true: package 57 // app calls package gl, but it has to do so in a separate goroutine, which 58 // means that its gl calls (which may be blocking) can race with other gl calls 59 // in the main program. We should make it safe to issue blocking gl calls 60 // concurrently, or get the gl calls out of package app, or both. 61 retvalue chan C.uintptr_t 62 63 cargs [workbufLen]C.struct_fnargs 64 parg [workbufLen]*C.char 65 } 66 67 func (ctx *context) WorkAvailable() <-chan struct{} { return ctx.workAvailable } 68 69 // NewContext creates a cgo OpenGL context. 70 // 71 // See the Worker interface for more details on how it is used. 72 func NewContext() (Context, Worker) { 73 glctx := &context{ 74 workAvailable: make(chan struct{}, 1), 75 work: make(chan call, workbufLen), 76 retvalue: make(chan C.uintptr_t), 77 } 78 return glctx, glctx 79 } 80 81 func (ctx *context) enqueue(c call) uintptr { 82 ctx.work <- c 83 84 select { 85 case ctx.workAvailable <- struct{}{}: 86 default: 87 } 88 89 if c.blocking { 90 return uintptr(<-ctx.retvalue) 91 } 92 return 0 93 } 94 95 func (ctx *context) DoWork() { 96 queue := make([]call, 0, workbufLen) 97 for { 98 // Wait until at least one piece of work is ready. 99 // Accumulate work until a piece is marked as blocking. 100 select { 101 case w := <-ctx.work: 102 queue = append(queue, w) 103 default: 104 return 105 } 106 blocking := queue[len(queue)-1].blocking 107 enqueue: 108 for len(queue) < cap(queue) && !blocking { 109 select { 110 case w := <-ctx.work: 111 queue = append(queue, w) 112 blocking = queue[len(queue)-1].blocking 113 default: 114 break enqueue 115 } 116 } 117 118 // Process the queued GL functions. 119 for i, q := range queue { 120 ctx.cargs[i] = *(*C.struct_fnargs)(unsafe.Pointer(&q.args)) 121 ctx.parg[i] = (*C.char)(q.parg) 122 } 123 ret := C.process(&ctx.cargs[0], ctx.parg[0], ctx.parg[1], ctx.parg[2], C.int(len(queue))) 124 125 // Cleanup and signal. 126 queue = queue[:0] 127 if blocking { 128 ctx.retvalue <- ret 129 } 130 } 131 } 132 133 func init() { 134 if unsafe.Sizeof(C.GLint(0)) != unsafe.Sizeof(int32(0)) { 135 panic("GLint is not an int32") 136 } 137 } 138 139 // cString creates C string off the Go heap. 140 // ret is a *char. 141 func (ctx *context) cString(str string) (uintptr, func()) { 142 ptr := unsafe.Pointer(C.CString(str)) 143 return uintptr(ptr), func() { C.free(ptr) } 144 } 145 146 // cString creates a pointer to a C string off the Go heap. 147 // ret is a **char. 148 func (ctx *context) cStringPtr(str string) (uintptr, func()) { 149 s, free := ctx.cString(str) 150 ptr := C.malloc(C.size_t(unsafe.Sizeof((*int)(nil)))) 151 *(*uintptr)(ptr) = s 152 return uintptr(ptr), func() { 153 free() 154 C.free(ptr) 155 } 156 }