github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/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  struct fnargs cargs[10];
    24  uintptr_t ret;
    25  
    26  void process(int count) {
    27  	int i;
    28  	for (i = 0; i < count; i++) {
    29  		processFn(&cargs[i]);
    30  	}
    31  }
    32  */
    33  import "C"
    34  
    35  // work is a queue of calls to execute.
    36  var work = make(chan call, 10)
    37  
    38  // retvalue is sent a return value when blocking calls complete.
    39  // It is safe to use a global unbuffered channel here as calls
    40  // cannot currently be made concurrently.
    41  //
    42  // TODO: the comment above about concurrent calls isn't actually true: package
    43  // app calls package gl, but it has to do so in a separate goroutine, which
    44  // means that its gl calls (which may be blocking) can race with other gl calls
    45  // in the main program. We should make it safe to issue blocking gl calls
    46  // concurrently, or get the gl calls out of package app, or both.
    47  var retvalue = make(chan C.uintptr_t)
    48  
    49  type call struct {
    50  	args     C.struct_fnargs
    51  	blocking bool
    52  }
    53  
    54  func enqueue(c call) C.uintptr_t {
    55  	work <- c
    56  
    57  	select {
    58  	case workAvailable <- struct{}{}:
    59  	default:
    60  	}
    61  
    62  	if c.blocking {
    63  		return <-retvalue
    64  	}
    65  	return 0
    66  }
    67  
    68  var (
    69  	workAvailable = make(chan struct{}, 1)
    70  	// WorkAvailable communicates when DoWork should be called.
    71  	//
    72  	// This is an internal implementation detail and should only be used by the
    73  	// github.com/c-darwin/mobile/app package.
    74  	WorkAvailable <-chan struct{} = workAvailable
    75  )
    76  
    77  // DoWork performs any pending OpenGL calls.
    78  //
    79  // This is an internal implementation detail and should only be used by the
    80  // github.com/c-darwin/mobile/app package.
    81  func DoWork() {
    82  	queue := make([]call, 0, len(work))
    83  	for {
    84  		// Wait until at least one piece of work is ready.
    85  		// Accumulate work until a piece is marked as blocking.
    86  		select {
    87  		case w := <-work:
    88  			queue = append(queue, w)
    89  		default:
    90  			return
    91  		}
    92  		blocking := queue[len(queue)-1].blocking
    93  	enqueue:
    94  		for len(queue) < cap(queue) && !blocking {
    95  			select {
    96  			case w := <-work:
    97  				queue = append(queue, w)
    98  				blocking = queue[len(queue)-1].blocking
    99  			default:
   100  				break enqueue
   101  			}
   102  		}
   103  
   104  		// Process the queued GL functions.
   105  		for i, q := range queue {
   106  			C.cargs[i] = q.args
   107  		}
   108  		C.process(C.int(len(queue)))
   109  
   110  		// Cleanup and signal.
   111  		queue = queue[:0]
   112  		if blocking {
   113  			retvalue <- C.ret
   114  		}
   115  	}
   116  }
   117  
   118  func glBoolean(b bool) C.uintptr_t {
   119  	if b {
   120  		return TRUE
   121  	}
   122  	return FALSE
   123  }