twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

work.go (4491B)


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