vendor dependencies, make some changes to how input is done
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
tags
|
||||||
|
whiteboard
|
||||||
@@ -1,35 +1,76 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/hajimehoshi/ebiten/v2"
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
type keymap []ebiten.Key
|
type keymap struct{
|
||||||
|
keys []ebiten.Key
|
||||||
|
mouseButtons []ebiten.MouseButton
|
||||||
|
}
|
||||||
|
|
||||||
var resize = keymap{
|
var resize = keymap{
|
||||||
ebiten.KeyD,
|
keys: []ebiten.Key{ebiten.KeyD, ebiten.KeyK,},
|
||||||
ebiten.KeyK,
|
|
||||||
}
|
}
|
||||||
var drawBlack = keymap{
|
var drawBlack = keymap{
|
||||||
ebiten.KeyF,
|
keys: []ebiten.Key{ebiten.KeyF, ebiten.KeyJ,},
|
||||||
ebiten.KeyJ,
|
|
||||||
}
|
}
|
||||||
var drawWhite = keymap{
|
var drawWhite = keymap{
|
||||||
ebiten.KeyS,
|
keys: []ebiten.Key{ebiten.KeyS, ebiten.KeyL,},
|
||||||
ebiten.KeyL,
|
|
||||||
}
|
}
|
||||||
var undo = keymap{
|
var undo = keymap{
|
||||||
ebiten.KeyZ,
|
keys: []ebiten.Key{ebiten.KeyZ, ebiten.KeyU,},
|
||||||
ebiten.KeyU,
|
|
||||||
}
|
}
|
||||||
var redo = keymap{
|
var redo = keymap{
|
||||||
ebiten.KeyX,
|
keys: []ebiten.Key{ebiten.KeyX, ebiten.KeyR,},
|
||||||
ebiten.KeyR,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k keymap) check(checker func(ebiten.Key) bool) bool {
|
func (k keymap) isJustPressed() bool {
|
||||||
for _, key := range k {
|
for _, key := range k.keys {
|
||||||
if checker(key) {
|
if inpututil.IsKeyJustPressed(key) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
for _, mouseButton := range k.mouseButtons {
|
||||||
|
if inpututil.IsMouseButtonJustPressed(mouseButton) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k keymap) isJustReleased() bool {
|
||||||
|
for _, key := range k.keys {
|
||||||
|
if inpututil.IsKeyJustReleased(key) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mouseButton := range k.mouseButtons {
|
||||||
|
if inpututil.IsMouseButtonJustReleased(mouseButton) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k keymap) isPressed() bool {
|
||||||
|
for _, key := range k.keys {
|
||||||
|
if ebiten.IsKeyPressed(key) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mouseButton := range k.mouseButtons {
|
||||||
|
if ebiten.IsMouseButtonPressed(mouseButton) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/vector"
|
"github.com/hajimehoshi/ebiten/v2/vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -56,17 +55,13 @@ func (a *app) Layout(_, _ int) (screenWidth int, screenHeight int) {
|
|||||||
|
|
||||||
func (a *app) Update() error {
|
func (a *app) Update() error {
|
||||||
|
|
||||||
check_any_drawing_input := func(checker func(ebiten.Key) bool) bool {
|
is_drawing := drawWhite.isPressed() || drawBlack.isPressed()
|
||||||
return drawWhite.check(checker) || drawBlack.check(checker)
|
just_started_drawing := drawWhite.isJustPressed() || drawBlack.isJustPressed()
|
||||||
}
|
|
||||||
|
|
||||||
is_drawing := check_any_drawing_input(ebiten.IsKeyPressed)
|
|
||||||
just_started_drawing := check_any_drawing_input(inpututil.IsKeyJustPressed)
|
|
||||||
|
|
||||||
var clr color.Color
|
var clr color.Color
|
||||||
if drawBlack.check(ebiten.IsKeyPressed) {
|
if drawBlack.isPressed() {
|
||||||
clr = color.Black
|
clr = color.Black
|
||||||
} else if drawWhite.check(ebiten.IsKeyPressed) {
|
} else if drawWhite.isPressed() {
|
||||||
clr = color.White
|
clr = color.White
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,11 +86,11 @@ func (a *app) Update() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resize.check(inpututil.IsKeyJustPressed) {
|
if resize.isJustPressed() {
|
||||||
a.sizeAnchorPos = cursorPosition()
|
a.sizeAnchorPos = cursorPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
if resize.check(ebiten.IsKeyPressed) {
|
if resize.isPressed() {
|
||||||
prevPos := a.sizeAnchorPos
|
prevPos := a.sizeAnchorPos
|
||||||
currPos := cursorPosition()
|
currPos := cursorPosition()
|
||||||
reltivePos := Vec2{
|
reltivePos := Vec2{
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package org.golang.app;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.NativeActivity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.KeyCharacterMap;
|
||||||
|
|
||||||
|
public class GoNativeActivity extends NativeActivity {
|
||||||
|
private static GoNativeActivity goNativeActivity;
|
||||||
|
|
||||||
|
public GoNativeActivity() {
|
||||||
|
super();
|
||||||
|
goNativeActivity = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getTmpdir() {
|
||||||
|
return getCacheDir().getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRune(int deviceId, int keyCode, int metaState) {
|
||||||
|
try {
|
||||||
|
int rune = KeyCharacterMap.load(deviceId).get(keyCode, metaState);
|
||||||
|
if (rune == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rune;
|
||||||
|
} catch (KeyCharacterMap.UnavailableException e) {
|
||||||
|
return -1;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Go", "exception reading KeyCharacterMap", e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load() {
|
||||||
|
// Interestingly, NativeActivity uses a different method
|
||||||
|
// to find native code to execute, avoiding
|
||||||
|
// System.loadLibrary. The result is Java methods
|
||||||
|
// implemented in C with JNIEXPORT (and JNI_OnLoad) are not
|
||||||
|
// available unless an explicit call to System.loadLibrary
|
||||||
|
// is done. So we do it here, borrowing the name of the
|
||||||
|
// library from the same AndroidManifest.xml metadata used
|
||||||
|
// by NativeActivity.
|
||||||
|
try {
|
||||||
|
ActivityInfo ai = getPackageManager().getActivityInfo(
|
||||||
|
getIntent().getComponent(), PackageManager.GET_META_DATA);
|
||||||
|
if (ai.metaData == null) {
|
||||||
|
Log.e("Go", "loadLibrary: no manifest metadata found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String libName = ai.metaData.getString("android.app.lib_name");
|
||||||
|
System.loadLibrary(libName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("Go", "loadLibrary failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
load();
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
}
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build android
|
||||||
|
// +build android
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
|
||||||
|
#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "Go", __VA_ARGS__)
|
||||||
|
#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go", __VA_ARGS__)
|
||||||
|
|
||||||
|
static jclass current_class;
|
||||||
|
|
||||||
|
static jclass find_class(JNIEnv *env, const char *class_name) {
|
||||||
|
jclass clazz = (*env)->FindClass(env, class_name);
|
||||||
|
if (clazz == NULL) {
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
LOG_FATAL("cannot find %s", class_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jmethodID find_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
||||||
|
jmethodID m = (*env)->GetMethodID(env, clazz, name, sig);
|
||||||
|
if (m == 0) {
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
LOG_FATAL("cannot find method %s %s", name, sig);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
|
||||||
|
jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig);
|
||||||
|
if (m == 0) {
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
LOG_FATAL("cannot find method %s %s", name, sig);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jmethodID key_rune_method;
|
||||||
|
|
||||||
|
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
|
JNIEnv* env;
|
||||||
|
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int main_running = 0;
|
||||||
|
|
||||||
|
// Entry point from our subclassed NativeActivity.
|
||||||
|
//
|
||||||
|
// By here, the Go runtime has been initialized (as we are running in
|
||||||
|
// -buildmode=c-shared) but the first time it is called, Go's main.main
|
||||||
|
// hasn't been called yet.
|
||||||
|
//
|
||||||
|
// The Activity may be created and destroyed multiple times throughout
|
||||||
|
// the life of a single process. Each time, onCreate is called.
|
||||||
|
void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) {
|
||||||
|
if (!main_running) {
|
||||||
|
JNIEnv* env = activity->env;
|
||||||
|
|
||||||
|
// Note that activity->clazz is mis-named.
|
||||||
|
current_class = (*env)->GetObjectClass(env, activity->clazz);
|
||||||
|
current_class = (*env)->NewGlobalRef(env, current_class);
|
||||||
|
key_rune_method = find_static_method(env, current_class, "getRune", "(III)I");
|
||||||
|
|
||||||
|
setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz));
|
||||||
|
|
||||||
|
// Set TMPDIR.
|
||||||
|
jmethodID gettmpdir = find_method(env, current_class, "getTmpdir", "()Ljava/lang/String;");
|
||||||
|
jstring jpath = (jstring)(*env)->CallObjectMethod(env, activity->clazz, gettmpdir, NULL);
|
||||||
|
const char* tmpdir = (*env)->GetStringUTFChars(env, jpath, NULL);
|
||||||
|
if (setenv("TMPDIR", tmpdir, 1) != 0) {
|
||||||
|
LOG_INFO("setenv(\"TMPDIR\", \"%s\", 1) failed: %d", tmpdir, errno);
|
||||||
|
}
|
||||||
|
(*env)->ReleaseStringUTFChars(env, jpath, tmpdir);
|
||||||
|
|
||||||
|
// Call the Go main.main.
|
||||||
|
uintptr_t mainPC = (uintptr_t)dlsym(RTLD_DEFAULT, "main.main");
|
||||||
|
if (!mainPC) {
|
||||||
|
LOG_FATAL("missing main.main");
|
||||||
|
}
|
||||||
|
callMain(mainPC);
|
||||||
|
main_running = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These functions match the methods on Activity, described at
|
||||||
|
// http://developer.android.com/reference/android/app/Activity.html
|
||||||
|
//
|
||||||
|
// Note that onNativeWindowResized is not called on resize. Avoid it.
|
||||||
|
// https://code.google.com/p/android/issues/detail?id=180645
|
||||||
|
activity->callbacks->onStart = onStart;
|
||||||
|
activity->callbacks->onResume = onResume;
|
||||||
|
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
|
||||||
|
activity->callbacks->onPause = onPause;
|
||||||
|
activity->callbacks->onStop = onStop;
|
||||||
|
activity->callbacks->onDestroy = onDestroy;
|
||||||
|
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
|
||||||
|
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
|
||||||
|
activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
|
||||||
|
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
|
||||||
|
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
|
||||||
|
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
|
||||||
|
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
|
||||||
|
activity->callbacks->onLowMemory = onLowMemory;
|
||||||
|
|
||||||
|
onCreate(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(crawshaw): Test configuration on more devices.
|
||||||
|
static const EGLint RGB_888[] = {
|
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_DEPTH_SIZE, 16,
|
||||||
|
EGL_CONFIG_CAVEAT, EGL_NONE,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
EGLDisplay display = NULL;
|
||||||
|
EGLSurface surface = NULL;
|
||||||
|
|
||||||
|
static char* initEGLDisplay() {
|
||||||
|
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
if (!eglInitialize(display, 0, 0)) {
|
||||||
|
return "EGL initialize failed";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* createEGLSurface(ANativeWindow* window) {
|
||||||
|
char* err;
|
||||||
|
EGLint numConfigs, format;
|
||||||
|
EGLConfig config;
|
||||||
|
EGLContext context;
|
||||||
|
|
||||||
|
if (display == 0) {
|
||||||
|
if ((err = initEGLDisplay()) != NULL) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
|
||||||
|
return "EGL choose RGB_888 config failed";
|
||||||
|
}
|
||||||
|
if (numConfigs <= 0) {
|
||||||
|
return "EGL no config found";
|
||||||
|
}
|
||||||
|
|
||||||
|
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||||
|
if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
|
||||||
|
return "EGL set buffers geometry failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = eglCreateWindowSurface(display, config, window, NULL);
|
||||||
|
if (surface == EGL_NO_SURFACE) {
|
||||||
|
return "EGL create surface failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
|
||||||
|
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
|
||||||
|
|
||||||
|
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
|
||||||
|
return "eglMakeCurrent failed";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* destroyEGLSurface() {
|
||||||
|
if (!eglDestroySurface(display, surface)) {
|
||||||
|
return "EGL destroy surface failed";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t getKeyRune(JNIEnv* env, AInputEvent* e) {
|
||||||
|
return (int32_t)(*env)->CallStaticIntMethod(
|
||||||
|
env,
|
||||||
|
current_class,
|
||||||
|
key_rune_method,
|
||||||
|
AInputEvent_getDeviceId(e),
|
||||||
|
AKeyEvent_getKeyCode(e),
|
||||||
|
AKeyEvent_getMetaState(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
+824
@@ -0,0 +1,824 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build android
|
||||||
|
|
||||||
|
/*
|
||||||
|
Android Apps are built with -buildmode=c-shared. They are loaded by a
|
||||||
|
running Java process.
|
||||||
|
|
||||||
|
Before any entry point is reached, a global constructor initializes the
|
||||||
|
Go runtime, calling all Go init functions. All cgo calls will block
|
||||||
|
until this is complete. Next JNI_OnLoad is called. When that is
|
||||||
|
complete, one of two entry points is called.
|
||||||
|
|
||||||
|
All-Go apps built using NativeActivity enter at ANativeActivity_onCreate.
|
||||||
|
|
||||||
|
Go libraries (for example, those built with gomobile bind) do not use
|
||||||
|
the app package initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -landroid -llog -lEGL -lGLESv2
|
||||||
|
|
||||||
|
#include <android/configuration.h>
|
||||||
|
#include <android/input.h>
|
||||||
|
#include <android/keycodes.h>
|
||||||
|
#include <android/looper.h>
|
||||||
|
#include <android/native_activity.h>
|
||||||
|
#include <android/native_window.h>
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
extern EGLDisplay display;
|
||||||
|
extern EGLSurface surface;
|
||||||
|
|
||||||
|
|
||||||
|
char* createEGLSurface(ANativeWindow* window);
|
||||||
|
char* destroyEGLSurface();
|
||||||
|
int32_t getKeyRune(JNIEnv* env, AInputEvent* e);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/app/internal/callfn"
|
||||||
|
"github.com/ebitengine/gomobile/event/key"
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/paint"
|
||||||
|
"github.com/ebitengine/gomobile/event/size"
|
||||||
|
"github.com/ebitengine/gomobile/event/touch"
|
||||||
|
"github.com/ebitengine/gomobile/geom"
|
||||||
|
"github.com/ebitengine/gomobile/internal/mobileinit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv.
|
||||||
|
//
|
||||||
|
// RunOnJVM blocks until the call to fn is complete. Any Java
|
||||||
|
// exception or failure to attach to the JVM is returned as an error.
|
||||||
|
//
|
||||||
|
// The function fn takes vm, the current JavaVM*,
|
||||||
|
// env, the current JNIEnv*, and
|
||||||
|
// ctx, a jobject representing the global android.context.Context.
|
||||||
|
func RunOnJVM(fn func(vm, jniEnv, ctx uintptr) error) error {
|
||||||
|
return mobileinit.RunOnJVM(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export setCurrentContext
|
||||||
|
func setCurrentContext(vm *C.JavaVM, ctx C.jobject) {
|
||||||
|
mobileinit.SetCurrentContext(unsafe.Pointer(vm), uintptr(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export callMain
|
||||||
|
func callMain(mainPC uintptr) {
|
||||||
|
for _, name := range []string{"TMPDIR", "PATH", "LD_LIBRARY_PATH"} {
|
||||||
|
n := C.CString(name)
|
||||||
|
os.Setenv(name, C.GoString(C.getenv(n)))
|
||||||
|
C.free(unsafe.Pointer(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timezone.
|
||||||
|
//
|
||||||
|
// Note that Android zoneinfo is stored in /system/usr/share/zoneinfo,
|
||||||
|
// but it is in some kind of packed TZiff file that we do not support
|
||||||
|
// yet. As a stopgap, we build a fixed zone using the tm_zone name.
|
||||||
|
var curtime C.time_t
|
||||||
|
var curtm C.struct_tm
|
||||||
|
C.time(&curtime)
|
||||||
|
C.localtime_r(&curtime, &curtm)
|
||||||
|
tzOffset := int(curtm.tm_gmtoff)
|
||||||
|
tz := C.GoString(curtm.tm_zone)
|
||||||
|
time.Local = time.FixedZone(tz, tzOffset)
|
||||||
|
|
||||||
|
go callfn.CallFn(mainPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onStart
|
||||||
|
func onStart(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onResume
|
||||||
|
func onResume(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onSaveInstanceState
|
||||||
|
func onSaveInstanceState(activity *C.ANativeActivity, outSize *C.size_t) unsafe.Pointer {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onPause
|
||||||
|
func onPause(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onStop
|
||||||
|
func onStop(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onCreate
|
||||||
|
func onCreate(activity *C.ANativeActivity) {
|
||||||
|
// Set the initial configuration.
|
||||||
|
//
|
||||||
|
// Note we use unbuffered channels to talk to the activity loop, and
|
||||||
|
// NativeActivity calls these callbacks sequentially, so configuration
|
||||||
|
// will be set before <-windowRedrawNeeded is processed.
|
||||||
|
windowConfigChange <- windowConfigRead(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onDestroy
|
||||||
|
func onDestroy(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onWindowFocusChanged
|
||||||
|
func onWindowFocusChanged(activity *C.ANativeActivity, hasFocus C.int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onNativeWindowCreated
|
||||||
|
func onNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindow) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onNativeWindowRedrawNeeded
|
||||||
|
func onNativeWindowRedrawNeeded(activity *C.ANativeActivity, window *C.ANativeWindow) {
|
||||||
|
// Called on orientation change and window resize.
|
||||||
|
// Send a request for redraw, and block this function
|
||||||
|
// until a complete draw and buffer swap is completed.
|
||||||
|
// This is required by the redraw documentation to
|
||||||
|
// avoid bad draws.
|
||||||
|
windowRedrawNeeded <- window
|
||||||
|
<-windowRedrawDone
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onNativeWindowDestroyed
|
||||||
|
func onNativeWindowDestroyed(activity *C.ANativeActivity, window *C.ANativeWindow) {
|
||||||
|
windowDestroyed <- window
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onInputQueueCreated
|
||||||
|
func onInputQueueCreated(activity *C.ANativeActivity, q *C.AInputQueue) {
|
||||||
|
inputQueue <- q
|
||||||
|
<-inputQueueDone
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onInputQueueDestroyed
|
||||||
|
func onInputQueueDestroyed(activity *C.ANativeActivity, q *C.AInputQueue) {
|
||||||
|
inputQueue <- nil
|
||||||
|
<-inputQueueDone
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onContentRectChanged
|
||||||
|
func onContentRectChanged(activity *C.ANativeActivity, rect *C.ARect) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type windowConfig struct {
|
||||||
|
orientation size.Orientation
|
||||||
|
pixelsPerPt float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func windowConfigRead(activity *C.ANativeActivity) windowConfig {
|
||||||
|
aconfig := C.AConfiguration_new()
|
||||||
|
C.AConfiguration_fromAssetManager(aconfig, activity.assetManager)
|
||||||
|
orient := C.AConfiguration_getOrientation(aconfig)
|
||||||
|
density := C.AConfiguration_getDensity(aconfig)
|
||||||
|
C.AConfiguration_delete(aconfig)
|
||||||
|
|
||||||
|
// Calculate the screen resolution. This value is approximate. For example,
|
||||||
|
// a physical resolution of 200 DPI may be quantized to one of the
|
||||||
|
// ACONFIGURATION_DENSITY_XXX values such as 160 or 240.
|
||||||
|
//
|
||||||
|
// A more accurate DPI could possibly be calculated from
|
||||||
|
// https://developer.android.com/reference/android/util/DisplayMetrics.html#xdpi
|
||||||
|
// but this does not appear to be accessible via the NDK. In any case, the
|
||||||
|
// hardware might not even provide a more accurate number, as the system
|
||||||
|
// does not apparently use the reported value. See golang.org/issue/13366
|
||||||
|
// for a discussion.
|
||||||
|
var dpi int
|
||||||
|
switch density {
|
||||||
|
case C.ACONFIGURATION_DENSITY_DEFAULT:
|
||||||
|
dpi = 160
|
||||||
|
case C.ACONFIGURATION_DENSITY_LOW,
|
||||||
|
C.ACONFIGURATION_DENSITY_MEDIUM,
|
||||||
|
213, // C.ACONFIGURATION_DENSITY_TV
|
||||||
|
C.ACONFIGURATION_DENSITY_HIGH,
|
||||||
|
320, // ACONFIGURATION_DENSITY_XHIGH
|
||||||
|
480, // ACONFIGURATION_DENSITY_XXHIGH
|
||||||
|
640: // ACONFIGURATION_DENSITY_XXXHIGH
|
||||||
|
dpi = int(density)
|
||||||
|
case C.ACONFIGURATION_DENSITY_NONE:
|
||||||
|
log.Print("android device reports no screen density")
|
||||||
|
dpi = 72
|
||||||
|
default:
|
||||||
|
log.Printf("android device reports unknown density: %d", density)
|
||||||
|
// All we can do is guess.
|
||||||
|
if density > 0 {
|
||||||
|
dpi = int(density)
|
||||||
|
} else {
|
||||||
|
dpi = 72
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o := size.OrientationUnknown
|
||||||
|
switch orient {
|
||||||
|
case C.ACONFIGURATION_ORIENTATION_PORT:
|
||||||
|
o = size.OrientationPortrait
|
||||||
|
case C.ACONFIGURATION_ORIENTATION_LAND:
|
||||||
|
o = size.OrientationLandscape
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowConfig{
|
||||||
|
orientation: o,
|
||||||
|
pixelsPerPt: float32(dpi) / 72,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onConfigurationChanged
|
||||||
|
func onConfigurationChanged(activity *C.ANativeActivity) {
|
||||||
|
// A rotation event first triggers onConfigurationChanged, then
|
||||||
|
// calls onNativeWindowRedrawNeeded. We extract the orientation
|
||||||
|
// here and save it for the redraw event.
|
||||||
|
windowConfigChange <- windowConfigRead(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onLowMemory
|
||||||
|
func onLowMemory(activity *C.ANativeActivity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
inputQueue = make(chan *C.AInputQueue)
|
||||||
|
inputQueueDone = make(chan struct{})
|
||||||
|
windowDestroyed = make(chan *C.ANativeWindow)
|
||||||
|
windowRedrawNeeded = make(chan *C.ANativeWindow)
|
||||||
|
windowRedrawDone = make(chan struct{})
|
||||||
|
windowConfigChange = make(chan windowConfig)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
theApp.registerGLViewportFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main(f func(App)) {
|
||||||
|
mainUserFn = f
|
||||||
|
// TODO: merge the runInputQueue and mainUI functions?
|
||||||
|
go func() {
|
||||||
|
if err := mobileinit.RunOnJVM(runInputQueue); err != nil {
|
||||||
|
log.Fatalf("app: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Preserve this OS thread for:
|
||||||
|
// 1. the attached JNI thread
|
||||||
|
// 2. the GL context
|
||||||
|
if err := mobileinit.RunOnJVM(mainUI); err != nil {
|
||||||
|
log.Fatalf("app: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mainUserFn func(App)
|
||||||
|
|
||||||
|
func mainUI(vm, jniEnv, ctx uintptr) error {
|
||||||
|
workAvailable := theApp.worker.WorkAvailable()
|
||||||
|
|
||||||
|
donec := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
// close the donec channel in a defer statement
|
||||||
|
// so that we could still be able to return even
|
||||||
|
// if mainUserFn panics.
|
||||||
|
defer close(donec)
|
||||||
|
|
||||||
|
mainUserFn(theApp)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var pixelsPerPt float32
|
||||||
|
var orientation size.Orientation
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-donec:
|
||||||
|
return nil
|
||||||
|
case cfg := <-windowConfigChange:
|
||||||
|
pixelsPerPt = cfg.pixelsPerPt
|
||||||
|
orientation = cfg.orientation
|
||||||
|
case w := <-windowRedrawNeeded:
|
||||||
|
if C.surface == nil {
|
||||||
|
if errStr := C.createEGLSurface(w); errStr != nil {
|
||||||
|
return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theApp.sendLifecycle(lifecycle.StageFocused)
|
||||||
|
widthPx := int(C.ANativeWindow_getWidth(w))
|
||||||
|
heightPx := int(C.ANativeWindow_getHeight(w))
|
||||||
|
theApp.eventsIn <- size.Event{
|
||||||
|
WidthPx: widthPx,
|
||||||
|
HeightPx: heightPx,
|
||||||
|
WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt),
|
||||||
|
HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt),
|
||||||
|
PixelsPerPt: pixelsPerPt,
|
||||||
|
Orientation: orientation,
|
||||||
|
}
|
||||||
|
theApp.eventsIn <- paint.Event{External: true}
|
||||||
|
case <-windowDestroyed:
|
||||||
|
if C.surface != nil {
|
||||||
|
if errStr := C.destroyEGLSurface(); errStr != nil {
|
||||||
|
return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C.surface = nil
|
||||||
|
theApp.sendLifecycle(lifecycle.StageAlive)
|
||||||
|
case <-workAvailable:
|
||||||
|
theApp.worker.DoWork()
|
||||||
|
case <-theApp.publish:
|
||||||
|
// TODO: compare a generation number to redrawGen for stale paints?
|
||||||
|
if C.surface != nil {
|
||||||
|
// eglSwapBuffers blocks until vsync.
|
||||||
|
if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
|
||||||
|
log.Printf("app: failed to swap buffers (%s)", eglGetError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case windowRedrawDone <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
theApp.publishResult <- PublishResult{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runInputQueue(vm, jniEnv, ctx uintptr) error {
|
||||||
|
env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer
|
||||||
|
|
||||||
|
// Android loopers select on OS file descriptors, not Go channels, so we
|
||||||
|
// translate the inputQueue channel to an ALooper_wake call.
|
||||||
|
l := C.ALooper_prepare(C.ALOOPER_PREPARE_ALLOW_NON_CALLBACKS)
|
||||||
|
pending := make(chan *C.AInputQueue, 1)
|
||||||
|
go func() {
|
||||||
|
for q := range inputQueue {
|
||||||
|
pending <- q
|
||||||
|
C.ALooper_wake(l)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var q *C.AInputQueue
|
||||||
|
for {
|
||||||
|
if C.ALooper_pollOnce(-1, nil, nil, nil) == C.ALOOPER_POLL_WAKE {
|
||||||
|
select {
|
||||||
|
default:
|
||||||
|
case p := <-pending:
|
||||||
|
if q != nil {
|
||||||
|
processEvents(env, q)
|
||||||
|
C.AInputQueue_detachLooper(q)
|
||||||
|
}
|
||||||
|
q = p
|
||||||
|
if q != nil {
|
||||||
|
C.AInputQueue_attachLooper(q, l, 0, nil, nil)
|
||||||
|
}
|
||||||
|
inputQueueDone <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if q != nil {
|
||||||
|
processEvents(env, q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processEvents(env *C.JNIEnv, q *C.AInputQueue) {
|
||||||
|
var e *C.AInputEvent
|
||||||
|
for C.AInputQueue_getEvent(q, &e) >= 0 {
|
||||||
|
if C.AInputQueue_preDispatchEvent(q, e) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processEvent(env, e)
|
||||||
|
C.AInputQueue_finishEvent(q, e, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processEvent(env *C.JNIEnv, e *C.AInputEvent) {
|
||||||
|
switch C.AInputEvent_getType(e) {
|
||||||
|
case C.AINPUT_EVENT_TYPE_KEY:
|
||||||
|
processKey(env, e)
|
||||||
|
case C.AINPUT_EVENT_TYPE_MOTION:
|
||||||
|
// At most one of the events in this batch is an up or down event; get its index and change.
|
||||||
|
upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
|
||||||
|
upDownType := touch.TypeMove
|
||||||
|
switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK {
|
||||||
|
case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN:
|
||||||
|
upDownType = touch.TypeBegin
|
||||||
|
case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP:
|
||||||
|
upDownType = touch.TypeEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ {
|
||||||
|
t := touch.TypeMove
|
||||||
|
if i == upDownIndex {
|
||||||
|
t = upDownType
|
||||||
|
}
|
||||||
|
theApp.eventsIn <- touch.Event{
|
||||||
|
X: float32(C.AMotionEvent_getX(e, i)),
|
||||||
|
Y: float32(C.AMotionEvent_getY(e, i)),
|
||||||
|
Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)),
|
||||||
|
Type: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processKey(env *C.JNIEnv, e *C.AInputEvent) {
|
||||||
|
deviceID := C.AInputEvent_getDeviceId(e)
|
||||||
|
if deviceID == 0 {
|
||||||
|
// Software keyboard input, leaving for scribe/IME.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
k := key.Event{
|
||||||
|
Rune: rune(C.getKeyRune(env, e)),
|
||||||
|
Code: convAndroidKeyCode(int32(C.AKeyEvent_getKeyCode(e))),
|
||||||
|
}
|
||||||
|
switch C.AKeyEvent_getAction(e) {
|
||||||
|
case C.AKEY_EVENT_ACTION_DOWN:
|
||||||
|
k.Direction = key.DirPress
|
||||||
|
case C.AKEY_EVENT_ACTION_UP:
|
||||||
|
k.Direction = key.DirRelease
|
||||||
|
default:
|
||||||
|
k.Direction = key.DirNone
|
||||||
|
}
|
||||||
|
// TODO(crawshaw): set Modifiers.
|
||||||
|
theApp.eventsIn <- k
|
||||||
|
}
|
||||||
|
|
||||||
|
func eglGetError() string {
|
||||||
|
switch errNum := C.eglGetError(); errNum {
|
||||||
|
case C.EGL_SUCCESS:
|
||||||
|
return "EGL_SUCCESS"
|
||||||
|
case C.EGL_NOT_INITIALIZED:
|
||||||
|
return "EGL_NOT_INITIALIZED"
|
||||||
|
case C.EGL_BAD_ACCESS:
|
||||||
|
return "EGL_BAD_ACCESS"
|
||||||
|
case C.EGL_BAD_ALLOC:
|
||||||
|
return "EGL_BAD_ALLOC"
|
||||||
|
case C.EGL_BAD_ATTRIBUTE:
|
||||||
|
return "EGL_BAD_ATTRIBUTE"
|
||||||
|
case C.EGL_BAD_CONTEXT:
|
||||||
|
return "EGL_BAD_CONTEXT"
|
||||||
|
case C.EGL_BAD_CONFIG:
|
||||||
|
return "EGL_BAD_CONFIG"
|
||||||
|
case C.EGL_BAD_CURRENT_SURFACE:
|
||||||
|
return "EGL_BAD_CURRENT_SURFACE"
|
||||||
|
case C.EGL_BAD_DISPLAY:
|
||||||
|
return "EGL_BAD_DISPLAY"
|
||||||
|
case C.EGL_BAD_SURFACE:
|
||||||
|
return "EGL_BAD_SURFACE"
|
||||||
|
case C.EGL_BAD_MATCH:
|
||||||
|
return "EGL_BAD_MATCH"
|
||||||
|
case C.EGL_BAD_PARAMETER:
|
||||||
|
return "EGL_BAD_PARAMETER"
|
||||||
|
case C.EGL_BAD_NATIVE_PIXMAP:
|
||||||
|
return "EGL_BAD_NATIVE_PIXMAP"
|
||||||
|
case C.EGL_BAD_NATIVE_WINDOW:
|
||||||
|
return "EGL_BAD_NATIVE_WINDOW"
|
||||||
|
case C.EGL_CONTEXT_LOST:
|
||||||
|
return "EGL_CONTEXT_LOST"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown EGL err: %d", errNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convAndroidKeyCode(aKeyCode int32) key.Code {
|
||||||
|
// Many Android key codes do not map into USB HID codes.
|
||||||
|
// For those, key.CodeUnknown is returned. This switch has all
|
||||||
|
// cases, even the unknown ones, to serve as a documentation
|
||||||
|
// and search aid.
|
||||||
|
switch aKeyCode {
|
||||||
|
case C.AKEYCODE_UNKNOWN:
|
||||||
|
case C.AKEYCODE_SOFT_LEFT:
|
||||||
|
case C.AKEYCODE_SOFT_RIGHT:
|
||||||
|
case C.AKEYCODE_HOME:
|
||||||
|
return key.CodeHome
|
||||||
|
case C.AKEYCODE_BACK:
|
||||||
|
case C.AKEYCODE_CALL:
|
||||||
|
case C.AKEYCODE_ENDCALL:
|
||||||
|
case C.AKEYCODE_0:
|
||||||
|
return key.Code0
|
||||||
|
case C.AKEYCODE_1:
|
||||||
|
return key.Code1
|
||||||
|
case C.AKEYCODE_2:
|
||||||
|
return key.Code2
|
||||||
|
case C.AKEYCODE_3:
|
||||||
|
return key.Code3
|
||||||
|
case C.AKEYCODE_4:
|
||||||
|
return key.Code4
|
||||||
|
case C.AKEYCODE_5:
|
||||||
|
return key.Code5
|
||||||
|
case C.AKEYCODE_6:
|
||||||
|
return key.Code6
|
||||||
|
case C.AKEYCODE_7:
|
||||||
|
return key.Code7
|
||||||
|
case C.AKEYCODE_8:
|
||||||
|
return key.Code8
|
||||||
|
case C.AKEYCODE_9:
|
||||||
|
return key.Code9
|
||||||
|
case C.AKEYCODE_STAR:
|
||||||
|
case C.AKEYCODE_POUND:
|
||||||
|
case C.AKEYCODE_DPAD_UP:
|
||||||
|
case C.AKEYCODE_DPAD_DOWN:
|
||||||
|
case C.AKEYCODE_DPAD_LEFT:
|
||||||
|
case C.AKEYCODE_DPAD_RIGHT:
|
||||||
|
case C.AKEYCODE_DPAD_CENTER:
|
||||||
|
case C.AKEYCODE_VOLUME_UP:
|
||||||
|
return key.CodeVolumeUp
|
||||||
|
case C.AKEYCODE_VOLUME_DOWN:
|
||||||
|
return key.CodeVolumeDown
|
||||||
|
case C.AKEYCODE_POWER:
|
||||||
|
case C.AKEYCODE_CAMERA:
|
||||||
|
case C.AKEYCODE_CLEAR:
|
||||||
|
case C.AKEYCODE_A:
|
||||||
|
return key.CodeA
|
||||||
|
case C.AKEYCODE_B:
|
||||||
|
return key.CodeB
|
||||||
|
case C.AKEYCODE_C:
|
||||||
|
return key.CodeC
|
||||||
|
case C.AKEYCODE_D:
|
||||||
|
return key.CodeD
|
||||||
|
case C.AKEYCODE_E:
|
||||||
|
return key.CodeE
|
||||||
|
case C.AKEYCODE_F:
|
||||||
|
return key.CodeF
|
||||||
|
case C.AKEYCODE_G:
|
||||||
|
return key.CodeG
|
||||||
|
case C.AKEYCODE_H:
|
||||||
|
return key.CodeH
|
||||||
|
case C.AKEYCODE_I:
|
||||||
|
return key.CodeI
|
||||||
|
case C.AKEYCODE_J:
|
||||||
|
return key.CodeJ
|
||||||
|
case C.AKEYCODE_K:
|
||||||
|
return key.CodeK
|
||||||
|
case C.AKEYCODE_L:
|
||||||
|
return key.CodeL
|
||||||
|
case C.AKEYCODE_M:
|
||||||
|
return key.CodeM
|
||||||
|
case C.AKEYCODE_N:
|
||||||
|
return key.CodeN
|
||||||
|
case C.AKEYCODE_O:
|
||||||
|
return key.CodeO
|
||||||
|
case C.AKEYCODE_P:
|
||||||
|
return key.CodeP
|
||||||
|
case C.AKEYCODE_Q:
|
||||||
|
return key.CodeQ
|
||||||
|
case C.AKEYCODE_R:
|
||||||
|
return key.CodeR
|
||||||
|
case C.AKEYCODE_S:
|
||||||
|
return key.CodeS
|
||||||
|
case C.AKEYCODE_T:
|
||||||
|
return key.CodeT
|
||||||
|
case C.AKEYCODE_U:
|
||||||
|
return key.CodeU
|
||||||
|
case C.AKEYCODE_V:
|
||||||
|
return key.CodeV
|
||||||
|
case C.AKEYCODE_W:
|
||||||
|
return key.CodeW
|
||||||
|
case C.AKEYCODE_X:
|
||||||
|
return key.CodeX
|
||||||
|
case C.AKEYCODE_Y:
|
||||||
|
return key.CodeY
|
||||||
|
case C.AKEYCODE_Z:
|
||||||
|
return key.CodeZ
|
||||||
|
case C.AKEYCODE_COMMA:
|
||||||
|
return key.CodeComma
|
||||||
|
case C.AKEYCODE_PERIOD:
|
||||||
|
return key.CodeFullStop
|
||||||
|
case C.AKEYCODE_ALT_LEFT:
|
||||||
|
return key.CodeLeftAlt
|
||||||
|
case C.AKEYCODE_ALT_RIGHT:
|
||||||
|
return key.CodeRightAlt
|
||||||
|
case C.AKEYCODE_SHIFT_LEFT:
|
||||||
|
return key.CodeLeftShift
|
||||||
|
case C.AKEYCODE_SHIFT_RIGHT:
|
||||||
|
return key.CodeRightShift
|
||||||
|
case C.AKEYCODE_TAB:
|
||||||
|
return key.CodeTab
|
||||||
|
case C.AKEYCODE_SPACE:
|
||||||
|
return key.CodeSpacebar
|
||||||
|
case C.AKEYCODE_SYM:
|
||||||
|
case C.AKEYCODE_EXPLORER:
|
||||||
|
case C.AKEYCODE_ENVELOPE:
|
||||||
|
case C.AKEYCODE_ENTER:
|
||||||
|
return key.CodeReturnEnter
|
||||||
|
case C.AKEYCODE_DEL:
|
||||||
|
return key.CodeDeleteBackspace
|
||||||
|
case C.AKEYCODE_GRAVE:
|
||||||
|
return key.CodeGraveAccent
|
||||||
|
case C.AKEYCODE_MINUS:
|
||||||
|
return key.CodeHyphenMinus
|
||||||
|
case C.AKEYCODE_EQUALS:
|
||||||
|
return key.CodeEqualSign
|
||||||
|
case C.AKEYCODE_LEFT_BRACKET:
|
||||||
|
return key.CodeLeftSquareBracket
|
||||||
|
case C.AKEYCODE_RIGHT_BRACKET:
|
||||||
|
return key.CodeRightSquareBracket
|
||||||
|
case C.AKEYCODE_BACKSLASH:
|
||||||
|
return key.CodeBackslash
|
||||||
|
case C.AKEYCODE_SEMICOLON:
|
||||||
|
return key.CodeSemicolon
|
||||||
|
case C.AKEYCODE_APOSTROPHE:
|
||||||
|
return key.CodeApostrophe
|
||||||
|
case C.AKEYCODE_SLASH:
|
||||||
|
return key.CodeSlash
|
||||||
|
case C.AKEYCODE_AT:
|
||||||
|
case C.AKEYCODE_NUM:
|
||||||
|
case C.AKEYCODE_HEADSETHOOK:
|
||||||
|
case C.AKEYCODE_FOCUS:
|
||||||
|
case C.AKEYCODE_PLUS:
|
||||||
|
case C.AKEYCODE_MENU:
|
||||||
|
case C.AKEYCODE_NOTIFICATION:
|
||||||
|
case C.AKEYCODE_SEARCH:
|
||||||
|
case C.AKEYCODE_MEDIA_PLAY_PAUSE:
|
||||||
|
case C.AKEYCODE_MEDIA_STOP:
|
||||||
|
case C.AKEYCODE_MEDIA_NEXT:
|
||||||
|
case C.AKEYCODE_MEDIA_PREVIOUS:
|
||||||
|
case C.AKEYCODE_MEDIA_REWIND:
|
||||||
|
case C.AKEYCODE_MEDIA_FAST_FORWARD:
|
||||||
|
case C.AKEYCODE_MUTE:
|
||||||
|
case C.AKEYCODE_PAGE_UP:
|
||||||
|
return key.CodePageUp
|
||||||
|
case C.AKEYCODE_PAGE_DOWN:
|
||||||
|
return key.CodePageDown
|
||||||
|
case C.AKEYCODE_PICTSYMBOLS:
|
||||||
|
case C.AKEYCODE_SWITCH_CHARSET:
|
||||||
|
case C.AKEYCODE_BUTTON_A:
|
||||||
|
case C.AKEYCODE_BUTTON_B:
|
||||||
|
case C.AKEYCODE_BUTTON_C:
|
||||||
|
case C.AKEYCODE_BUTTON_X:
|
||||||
|
case C.AKEYCODE_BUTTON_Y:
|
||||||
|
case C.AKEYCODE_BUTTON_Z:
|
||||||
|
case C.AKEYCODE_BUTTON_L1:
|
||||||
|
case C.AKEYCODE_BUTTON_R1:
|
||||||
|
case C.AKEYCODE_BUTTON_L2:
|
||||||
|
case C.AKEYCODE_BUTTON_R2:
|
||||||
|
case C.AKEYCODE_BUTTON_THUMBL:
|
||||||
|
case C.AKEYCODE_BUTTON_THUMBR:
|
||||||
|
case C.AKEYCODE_BUTTON_START:
|
||||||
|
case C.AKEYCODE_BUTTON_SELECT:
|
||||||
|
case C.AKEYCODE_BUTTON_MODE:
|
||||||
|
case C.AKEYCODE_ESCAPE:
|
||||||
|
return key.CodeEscape
|
||||||
|
case C.AKEYCODE_FORWARD_DEL:
|
||||||
|
return key.CodeDeleteForward
|
||||||
|
case C.AKEYCODE_CTRL_LEFT:
|
||||||
|
return key.CodeLeftControl
|
||||||
|
case C.AKEYCODE_CTRL_RIGHT:
|
||||||
|
return key.CodeRightControl
|
||||||
|
case C.AKEYCODE_CAPS_LOCK:
|
||||||
|
return key.CodeCapsLock
|
||||||
|
case C.AKEYCODE_SCROLL_LOCK:
|
||||||
|
case C.AKEYCODE_META_LEFT:
|
||||||
|
return key.CodeLeftGUI
|
||||||
|
case C.AKEYCODE_META_RIGHT:
|
||||||
|
return key.CodeRightGUI
|
||||||
|
case C.AKEYCODE_FUNCTION:
|
||||||
|
case C.AKEYCODE_SYSRQ:
|
||||||
|
case C.AKEYCODE_BREAK:
|
||||||
|
case C.AKEYCODE_MOVE_HOME:
|
||||||
|
case C.AKEYCODE_MOVE_END:
|
||||||
|
case C.AKEYCODE_INSERT:
|
||||||
|
return key.CodeInsert
|
||||||
|
case C.AKEYCODE_FORWARD:
|
||||||
|
case C.AKEYCODE_MEDIA_PLAY:
|
||||||
|
case C.AKEYCODE_MEDIA_PAUSE:
|
||||||
|
case C.AKEYCODE_MEDIA_CLOSE:
|
||||||
|
case C.AKEYCODE_MEDIA_EJECT:
|
||||||
|
case C.AKEYCODE_MEDIA_RECORD:
|
||||||
|
case C.AKEYCODE_F1:
|
||||||
|
return key.CodeF1
|
||||||
|
case C.AKEYCODE_F2:
|
||||||
|
return key.CodeF2
|
||||||
|
case C.AKEYCODE_F3:
|
||||||
|
return key.CodeF3
|
||||||
|
case C.AKEYCODE_F4:
|
||||||
|
return key.CodeF4
|
||||||
|
case C.AKEYCODE_F5:
|
||||||
|
return key.CodeF5
|
||||||
|
case C.AKEYCODE_F6:
|
||||||
|
return key.CodeF6
|
||||||
|
case C.AKEYCODE_F7:
|
||||||
|
return key.CodeF7
|
||||||
|
case C.AKEYCODE_F8:
|
||||||
|
return key.CodeF8
|
||||||
|
case C.AKEYCODE_F9:
|
||||||
|
return key.CodeF9
|
||||||
|
case C.AKEYCODE_F10:
|
||||||
|
return key.CodeF10
|
||||||
|
case C.AKEYCODE_F11:
|
||||||
|
return key.CodeF11
|
||||||
|
case C.AKEYCODE_F12:
|
||||||
|
return key.CodeF12
|
||||||
|
case C.AKEYCODE_NUM_LOCK:
|
||||||
|
return key.CodeKeypadNumLock
|
||||||
|
case C.AKEYCODE_NUMPAD_0:
|
||||||
|
return key.CodeKeypad0
|
||||||
|
case C.AKEYCODE_NUMPAD_1:
|
||||||
|
return key.CodeKeypad1
|
||||||
|
case C.AKEYCODE_NUMPAD_2:
|
||||||
|
return key.CodeKeypad2
|
||||||
|
case C.AKEYCODE_NUMPAD_3:
|
||||||
|
return key.CodeKeypad3
|
||||||
|
case C.AKEYCODE_NUMPAD_4:
|
||||||
|
return key.CodeKeypad4
|
||||||
|
case C.AKEYCODE_NUMPAD_5:
|
||||||
|
return key.CodeKeypad5
|
||||||
|
case C.AKEYCODE_NUMPAD_6:
|
||||||
|
return key.CodeKeypad6
|
||||||
|
case C.AKEYCODE_NUMPAD_7:
|
||||||
|
return key.CodeKeypad7
|
||||||
|
case C.AKEYCODE_NUMPAD_8:
|
||||||
|
return key.CodeKeypad8
|
||||||
|
case C.AKEYCODE_NUMPAD_9:
|
||||||
|
return key.CodeKeypad9
|
||||||
|
case C.AKEYCODE_NUMPAD_DIVIDE:
|
||||||
|
return key.CodeKeypadSlash
|
||||||
|
case C.AKEYCODE_NUMPAD_MULTIPLY:
|
||||||
|
return key.CodeKeypadAsterisk
|
||||||
|
case C.AKEYCODE_NUMPAD_SUBTRACT:
|
||||||
|
return key.CodeKeypadHyphenMinus
|
||||||
|
case C.AKEYCODE_NUMPAD_ADD:
|
||||||
|
return key.CodeKeypadPlusSign
|
||||||
|
case C.AKEYCODE_NUMPAD_DOT:
|
||||||
|
return key.CodeKeypadFullStop
|
||||||
|
case C.AKEYCODE_NUMPAD_COMMA:
|
||||||
|
case C.AKEYCODE_NUMPAD_ENTER:
|
||||||
|
return key.CodeKeypadEnter
|
||||||
|
case C.AKEYCODE_NUMPAD_EQUALS:
|
||||||
|
return key.CodeKeypadEqualSign
|
||||||
|
case C.AKEYCODE_NUMPAD_LEFT_PAREN:
|
||||||
|
case C.AKEYCODE_NUMPAD_RIGHT_PAREN:
|
||||||
|
case C.AKEYCODE_VOLUME_MUTE:
|
||||||
|
return key.CodeMute
|
||||||
|
case C.AKEYCODE_INFO:
|
||||||
|
case C.AKEYCODE_CHANNEL_UP:
|
||||||
|
case C.AKEYCODE_CHANNEL_DOWN:
|
||||||
|
case C.AKEYCODE_ZOOM_IN:
|
||||||
|
case C.AKEYCODE_ZOOM_OUT:
|
||||||
|
case C.AKEYCODE_TV:
|
||||||
|
case C.AKEYCODE_WINDOW:
|
||||||
|
case C.AKEYCODE_GUIDE:
|
||||||
|
case C.AKEYCODE_DVR:
|
||||||
|
case C.AKEYCODE_BOOKMARK:
|
||||||
|
case C.AKEYCODE_CAPTIONS:
|
||||||
|
case C.AKEYCODE_SETTINGS:
|
||||||
|
case C.AKEYCODE_TV_POWER:
|
||||||
|
case C.AKEYCODE_TV_INPUT:
|
||||||
|
case C.AKEYCODE_STB_POWER:
|
||||||
|
case C.AKEYCODE_STB_INPUT:
|
||||||
|
case C.AKEYCODE_AVR_POWER:
|
||||||
|
case C.AKEYCODE_AVR_INPUT:
|
||||||
|
case C.AKEYCODE_PROG_RED:
|
||||||
|
case C.AKEYCODE_PROG_GREEN:
|
||||||
|
case C.AKEYCODE_PROG_YELLOW:
|
||||||
|
case C.AKEYCODE_PROG_BLUE:
|
||||||
|
case C.AKEYCODE_APP_SWITCH:
|
||||||
|
case C.AKEYCODE_BUTTON_1:
|
||||||
|
case C.AKEYCODE_BUTTON_2:
|
||||||
|
case C.AKEYCODE_BUTTON_3:
|
||||||
|
case C.AKEYCODE_BUTTON_4:
|
||||||
|
case C.AKEYCODE_BUTTON_5:
|
||||||
|
case C.AKEYCODE_BUTTON_6:
|
||||||
|
case C.AKEYCODE_BUTTON_7:
|
||||||
|
case C.AKEYCODE_BUTTON_8:
|
||||||
|
case C.AKEYCODE_BUTTON_9:
|
||||||
|
case C.AKEYCODE_BUTTON_10:
|
||||||
|
case C.AKEYCODE_BUTTON_11:
|
||||||
|
case C.AKEYCODE_BUTTON_12:
|
||||||
|
case C.AKEYCODE_BUTTON_13:
|
||||||
|
case C.AKEYCODE_BUTTON_14:
|
||||||
|
case C.AKEYCODE_BUTTON_15:
|
||||||
|
case C.AKEYCODE_BUTTON_16:
|
||||||
|
case C.AKEYCODE_LANGUAGE_SWITCH:
|
||||||
|
case C.AKEYCODE_MANNER_MODE:
|
||||||
|
case C.AKEYCODE_3D_MODE:
|
||||||
|
case C.AKEYCODE_CONTACTS:
|
||||||
|
case C.AKEYCODE_CALENDAR:
|
||||||
|
case C.AKEYCODE_MUSIC:
|
||||||
|
case C.AKEYCODE_CALCULATOR:
|
||||||
|
}
|
||||||
|
/* Defined in an NDK API version beyond what we use today:
|
||||||
|
C.AKEYCODE_ASSIST
|
||||||
|
C.AKEYCODE_BRIGHTNESS_DOWN
|
||||||
|
C.AKEYCODE_BRIGHTNESS_UP
|
||||||
|
C.AKEYCODE_EISU
|
||||||
|
C.AKEYCODE_HENKAN
|
||||||
|
C.AKEYCODE_KANA
|
||||||
|
C.AKEYCODE_KATAKANA_HIRAGANA
|
||||||
|
C.AKEYCODE_MEDIA_AUDIO_TRACK
|
||||||
|
C.AKEYCODE_MUHENKAN
|
||||||
|
C.AKEYCODE_RO
|
||||||
|
C.AKEYCODE_YEN
|
||||||
|
C.AKEYCODE_ZENKAKU_HANKAKU
|
||||||
|
*/
|
||||||
|
return key.CodeUnknown
|
||||||
|
}
|
||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build linux || darwin || windows
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/size"
|
||||||
|
"github.com/ebitengine/gomobile/gl"
|
||||||
|
_ "github.com/ebitengine/gomobile/internal/mobileinit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Main is called by the main.main function to run the mobile application.
|
||||||
|
//
|
||||||
|
// It calls f on the App, in a separate goroutine, as some OS-specific
|
||||||
|
// libraries require being on 'the main thread'.
|
||||||
|
func Main(f func(App)) {
|
||||||
|
main(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// App is how a GUI mobile application interacts with the OS.
|
||||||
|
type App interface {
|
||||||
|
// Events returns the events channel. It carries events from the system to
|
||||||
|
// the app. The type of such events include:
|
||||||
|
// - lifecycle.Event
|
||||||
|
// - mouse.Event
|
||||||
|
// - paint.Event
|
||||||
|
// - size.Event
|
||||||
|
// - touch.Event
|
||||||
|
// from the github.com/ebitengine/gomobile/event/etc packages. Other packages may
|
||||||
|
// define other event types that are carried on this channel.
|
||||||
|
Events() <-chan interface{}
|
||||||
|
|
||||||
|
// Send sends an event on the events channel. It does not block.
|
||||||
|
Send(event interface{})
|
||||||
|
|
||||||
|
// Publish flushes any pending drawing commands, such as OpenGL calls, and
|
||||||
|
// swaps the back buffer to the screen.
|
||||||
|
Publish() PublishResult
|
||||||
|
|
||||||
|
// TODO: replace filters (and the Events channel) with a NextEvent method?
|
||||||
|
|
||||||
|
// Filter calls each registered event filter function in sequence.
|
||||||
|
Filter(event interface{}) interface{}
|
||||||
|
|
||||||
|
// RegisterFilter registers a event filter function to be called by Filter. The
|
||||||
|
// function can return a different event, or return nil to consume the event,
|
||||||
|
// but the function can also return its argument unchanged, where its purpose
|
||||||
|
// is to trigger a side effect rather than modify the event.
|
||||||
|
RegisterFilter(f func(interface{}) interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublishResult is the result of an App.Publish call.
|
||||||
|
type PublishResult struct {
|
||||||
|
// BackBufferPreserved is whether the contents of the back buffer was
|
||||||
|
// preserved. If false, the contents are undefined.
|
||||||
|
BackBufferPreserved bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var theApp = &app{
|
||||||
|
eventsOut: make(chan interface{}),
|
||||||
|
lifecycleStage: lifecycle.StageDead,
|
||||||
|
publish: make(chan struct{}),
|
||||||
|
publishResult: make(chan PublishResult),
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
theApp.eventsIn = pump(theApp.eventsOut)
|
||||||
|
theApp.glctx, theApp.worker = gl.NewContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) sendLifecycle(to lifecycle.Stage) {
|
||||||
|
if a.lifecycleStage == to {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.eventsIn <- lifecycle.Event{
|
||||||
|
From: a.lifecycleStage,
|
||||||
|
To: to,
|
||||||
|
DrawContext: a.glctx,
|
||||||
|
}
|
||||||
|
a.lifecycleStage = to
|
||||||
|
}
|
||||||
|
|
||||||
|
type app struct {
|
||||||
|
filters []func(interface{}) interface{}
|
||||||
|
|
||||||
|
eventsOut chan interface{}
|
||||||
|
eventsIn chan interface{}
|
||||||
|
lifecycleStage lifecycle.Stage
|
||||||
|
publish chan struct{}
|
||||||
|
publishResult chan PublishResult
|
||||||
|
|
||||||
|
glctx gl.Context
|
||||||
|
worker gl.Worker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) Events() <-chan interface{} {
|
||||||
|
return a.eventsOut
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) Send(event interface{}) {
|
||||||
|
a.eventsIn <- event
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) Publish() PublishResult {
|
||||||
|
// gl.Flush is a lightweight (on modern GL drivers) blocking call
|
||||||
|
// that ensures all GL functions pending in the gl package have
|
||||||
|
// been passed onto the GL driver before the app package attempts
|
||||||
|
// to swap the screen buffer.
|
||||||
|
//
|
||||||
|
// This enforces that the final receive (for this paint cycle) on
|
||||||
|
// gl.WorkAvailable happens before the send on endPaint.
|
||||||
|
a.glctx.Flush()
|
||||||
|
a.publish <- struct{}{}
|
||||||
|
return <-a.publishResult
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) Filter(event interface{}) interface{} {
|
||||||
|
for _, f := range a.filters {
|
||||||
|
event = f(event)
|
||||||
|
}
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) RegisterFilter(f func(interface{}) interface{}) {
|
||||||
|
a.filters = append(a.filters, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stopPumping struct{}
|
||||||
|
|
||||||
|
// pump returns a channel src such that sending on src will eventually send on
|
||||||
|
// dst, in order, but that src will always be ready to send/receive soon, even
|
||||||
|
// if dst currently isn't. It is effectively an infinitely buffered channel.
|
||||||
|
//
|
||||||
|
// In particular, goroutine A sending on src will not deadlock even if goroutine
|
||||||
|
// B that's responsible for receiving on dst is currently blocked trying to
|
||||||
|
// send to A on a separate channel.
|
||||||
|
//
|
||||||
|
// Send a stopPumping on the src channel to close the dst channel after all queued
|
||||||
|
// events are sent on dst. After that, other goroutines can still send to src,
|
||||||
|
// so that such sends won't block forever, but such events will be ignored.
|
||||||
|
func pump(dst chan interface{}) (src chan interface{}) {
|
||||||
|
src = make(chan interface{})
|
||||||
|
go func() {
|
||||||
|
// initialSize is the initial size of the circular buffer. It must be a
|
||||||
|
// power of 2.
|
||||||
|
const initialSize = 16
|
||||||
|
i, j, buf, mask := 0, 0, make([]interface{}, initialSize), initialSize-1
|
||||||
|
|
||||||
|
srcActive := true
|
||||||
|
for {
|
||||||
|
maybeDst := dst
|
||||||
|
if i == j {
|
||||||
|
maybeDst = nil
|
||||||
|
}
|
||||||
|
if maybeDst == nil && !srcActive {
|
||||||
|
// Pump is stopped and empty.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case maybeDst <- buf[i&mask]:
|
||||||
|
buf[i&mask] = nil
|
||||||
|
i++
|
||||||
|
|
||||||
|
case e := <-src:
|
||||||
|
if _, ok := e.(stopPumping); ok {
|
||||||
|
srcActive = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !srcActive {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a bigger buffer if necessary.
|
||||||
|
if i+len(buf) == j {
|
||||||
|
b := make([]interface{}, 2*len(buf))
|
||||||
|
n := copy(b, buf[j&mask:])
|
||||||
|
copy(b[n:], buf[:j&mask])
|
||||||
|
i, j = 0, len(buf)
|
||||||
|
buf, mask = b, len(b)-1
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[j&mask] = e
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(dst)
|
||||||
|
// Block forever.
|
||||||
|
for range src {
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do this for all build targets, not just linux (x11 and Android)? If
|
||||||
|
// so, should package gl instead of this package call RegisterFilter??
|
||||||
|
//
|
||||||
|
// TODO: does Android need this?? It seems to work without it (Nexus 7,
|
||||||
|
// KitKat). If only x11 needs this, should we move this to x11.go??
|
||||||
|
func (a *app) registerGLViewportFilter() {
|
||||||
|
a.RegisterFilter(func(e interface{}) interface{} {
|
||||||
|
if e, ok := e.(size.Event); ok {
|
||||||
|
a.glctx.Viewport(0, 0, e.WidthPx, e.HeightPx)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
})
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// 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 app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main(f func(a App)) {
|
||||||
|
log.Fatal("main is not implemented on Windows")
|
||||||
|
}
|
||||||
+495
@@ -0,0 +1,495 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin && !ios
|
||||||
|
|
||||||
|
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 -DGL_SILENCE_DEPRECATION
|
||||||
|
#cgo LDFLAGS: -framework Cocoa -framework OpenGL
|
||||||
|
#import <Carbon/Carbon.h> // for HIToolbox/Events.h
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void runApp(void);
|
||||||
|
void stopApp(void);
|
||||||
|
void makeCurrentContext(GLintptr);
|
||||||
|
uint64 threadID();
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/event/key"
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/paint"
|
||||||
|
"github.com/ebitengine/gomobile/event/size"
|
||||||
|
"github.com/ebitengine/gomobile/event/touch"
|
||||||
|
"github.com/ebitengine/gomobile/geom"
|
||||||
|
)
|
||||||
|
|
||||||
|
var initThreadID uint64
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Lock the goroutine responsible for initialization to an OS thread.
|
||||||
|
// This means the goroutine running main (and calling runApp 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 main(f func(App)) {
|
||||||
|
if tid := uint64(C.threadID()); tid != initThreadID {
|
||||||
|
log.Fatalf("app.Main called on thread %d, but app.init ran on %d", tid, initThreadID)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
f(theApp)
|
||||||
|
C.stopApp()
|
||||||
|
}()
|
||||||
|
|
||||||
|
C.runApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop is the primary drawing loop.
|
||||||
|
//
|
||||||
|
// After Cocoa has captured the initial OS thread for processing Cocoa
|
||||||
|
// events in runApp, it starts loop on another goroutine. It is locked
|
||||||
|
// to an OS thread for its OpenGL context.
|
||||||
|
//
|
||||||
|
// The loop processes GL calls until a publish event appears.
|
||||||
|
// Then it runs any remaining GL calls and flushes the screen.
|
||||||
|
//
|
||||||
|
// As NSOpenGLCPSwapInterval is set to 1, the call to CGLFlushDrawable
|
||||||
|
// blocks until the screen refresh.
|
||||||
|
func (a *app) loop(ctx C.GLintptr) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
C.makeCurrentContext(ctx)
|
||||||
|
|
||||||
|
workAvailable := a.worker.WorkAvailable()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-workAvailable:
|
||||||
|
a.worker.DoWork()
|
||||||
|
case <-theApp.publish:
|
||||||
|
loop1:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-workAvailable:
|
||||||
|
a.worker.DoWork()
|
||||||
|
default:
|
||||||
|
break loop1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C.CGLFlushDrawable(C.CGLGetCurrentContext())
|
||||||
|
theApp.publishResult <- PublishResult{}
|
||||||
|
select {
|
||||||
|
case drawDone <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var drawDone = make(chan struct{})
|
||||||
|
|
||||||
|
// drawgl is used by Cocoa to occasionally request screen updates.
|
||||||
|
//
|
||||||
|
//export drawgl
|
||||||
|
func drawgl() {
|
||||||
|
switch theApp.lifecycleStage {
|
||||||
|
case lifecycle.StageFocused, lifecycle.StageVisible:
|
||||||
|
theApp.Send(paint.Event{
|
||||||
|
External: true,
|
||||||
|
})
|
||||||
|
<-drawDone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export startloop
|
||||||
|
func startloop(ctx C.GLintptr) {
|
||||||
|
go theApp.loop(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
var windowHeightPx float32
|
||||||
|
|
||||||
|
//export setGeom
|
||||||
|
func setGeom(pixelsPerPt float32, widthPx, heightPx int) {
|
||||||
|
windowHeightPx = float32(heightPx)
|
||||||
|
theApp.eventsIn <- size.Event{
|
||||||
|
WidthPx: widthPx,
|
||||||
|
HeightPx: heightPx,
|
||||||
|
WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt),
|
||||||
|
HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt),
|
||||||
|
PixelsPerPt: pixelsPerPt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var touchEvents struct {
|
||||||
|
sync.Mutex
|
||||||
|
pending []touch.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendTouch(t touch.Type, x, y float32) {
|
||||||
|
theApp.eventsIn <- touch.Event{
|
||||||
|
X: x,
|
||||||
|
Y: windowHeightPx - y,
|
||||||
|
Sequence: 0,
|
||||||
|
Type: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export eventMouseDown
|
||||||
|
func eventMouseDown(x, y float32) { sendTouch(touch.TypeBegin, x, y) }
|
||||||
|
|
||||||
|
//export eventMouseDragged
|
||||||
|
func eventMouseDragged(x, y float32) { sendTouch(touch.TypeMove, x, y) }
|
||||||
|
|
||||||
|
//export eventMouseEnd
|
||||||
|
func eventMouseEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
|
||||||
|
|
||||||
|
//export lifecycleDead
|
||||||
|
func lifecycleDead() { theApp.sendLifecycle(lifecycle.StageDead) }
|
||||||
|
|
||||||
|
//export eventKey
|
||||||
|
func eventKey(runeVal int32, direction uint8, code uint16, flags uint32) {
|
||||||
|
var modifiers key.Modifiers
|
||||||
|
for _, mod := range mods {
|
||||||
|
if flags&mod.flags == mod.flags {
|
||||||
|
modifiers |= mod.mod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
theApp.eventsIn <- key.Event{
|
||||||
|
Rune: convRune(rune(runeVal)),
|
||||||
|
Code: convVirtualKeyCode(code),
|
||||||
|
Modifiers: modifiers,
|
||||||
|
Direction: key.Direction(direction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export eventFlags
|
||||||
|
func eventFlags(flags uint32) {
|
||||||
|
for _, mod := range mods {
|
||||||
|
if flags&mod.flags == mod.flags && lastFlags&mod.flags != mod.flags {
|
||||||
|
eventKey(-1, uint8(key.DirPress), mod.code, flags)
|
||||||
|
}
|
||||||
|
if lastFlags&mod.flags == mod.flags && flags&mod.flags != mod.flags {
|
||||||
|
eventKey(-1, uint8(key.DirRelease), mod.code, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastFlags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastFlags uint32
|
||||||
|
|
||||||
|
var mods = [...]struct {
|
||||||
|
flags uint32
|
||||||
|
code uint16
|
||||||
|
mod key.Modifiers
|
||||||
|
}{
|
||||||
|
// Left and right variants of modifier keys have their own masks,
|
||||||
|
// but they are not documented. These were determined empirically.
|
||||||
|
{1<<17 | 0x102, C.kVK_Shift, key.ModShift},
|
||||||
|
{1<<17 | 0x104, C.kVK_RightShift, key.ModShift},
|
||||||
|
{1<<18 | 0x101, C.kVK_Control, key.ModControl},
|
||||||
|
// TODO key.ControlRight
|
||||||
|
{1<<19 | 0x120, C.kVK_Option, key.ModAlt},
|
||||||
|
{1<<19 | 0x140, C.kVK_RightOption, key.ModAlt},
|
||||||
|
{1<<20 | 0x108, C.kVK_Command, key.ModMeta},
|
||||||
|
{1<<20 | 0x110, C.kVK_Command, key.ModMeta}, // TODO: missing kVK_RightCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
//export lifecycleAlive
|
||||||
|
func lifecycleAlive() { theApp.sendLifecycle(lifecycle.StageAlive) }
|
||||||
|
|
||||||
|
//export lifecycleVisible
|
||||||
|
func lifecycleVisible() {
|
||||||
|
theApp.sendLifecycle(lifecycle.StageVisible)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export lifecycleFocused
|
||||||
|
func lifecycleFocused() { theApp.sendLifecycle(lifecycle.StageFocused) }
|
||||||
|
|
||||||
|
// convRune marks the Carbon/Cocoa private-range unicode rune representing
|
||||||
|
// a non-unicode key event to -1, used for Rune in the key package.
|
||||||
|
//
|
||||||
|
// http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
|
||||||
|
func convRune(r rune) rune {
|
||||||
|
if '\uE000' <= r && r <= '\uF8FF' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// convVirtualKeyCode converts a Carbon/Cocoa virtual key code number
|
||||||
|
// into the standard keycodes used by the key package.
|
||||||
|
//
|
||||||
|
// To get a sense of the key map, see the diagram on
|
||||||
|
//
|
||||||
|
// http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes
|
||||||
|
func convVirtualKeyCode(vkcode uint16) key.Code {
|
||||||
|
switch vkcode {
|
||||||
|
case C.kVK_ANSI_A:
|
||||||
|
return key.CodeA
|
||||||
|
case C.kVK_ANSI_B:
|
||||||
|
return key.CodeB
|
||||||
|
case C.kVK_ANSI_C:
|
||||||
|
return key.CodeC
|
||||||
|
case C.kVK_ANSI_D:
|
||||||
|
return key.CodeD
|
||||||
|
case C.kVK_ANSI_E:
|
||||||
|
return key.CodeE
|
||||||
|
case C.kVK_ANSI_F:
|
||||||
|
return key.CodeF
|
||||||
|
case C.kVK_ANSI_G:
|
||||||
|
return key.CodeG
|
||||||
|
case C.kVK_ANSI_H:
|
||||||
|
return key.CodeH
|
||||||
|
case C.kVK_ANSI_I:
|
||||||
|
return key.CodeI
|
||||||
|
case C.kVK_ANSI_J:
|
||||||
|
return key.CodeJ
|
||||||
|
case C.kVK_ANSI_K:
|
||||||
|
return key.CodeK
|
||||||
|
case C.kVK_ANSI_L:
|
||||||
|
return key.CodeL
|
||||||
|
case C.kVK_ANSI_M:
|
||||||
|
return key.CodeM
|
||||||
|
case C.kVK_ANSI_N:
|
||||||
|
return key.CodeN
|
||||||
|
case C.kVK_ANSI_O:
|
||||||
|
return key.CodeO
|
||||||
|
case C.kVK_ANSI_P:
|
||||||
|
return key.CodeP
|
||||||
|
case C.kVK_ANSI_Q:
|
||||||
|
return key.CodeQ
|
||||||
|
case C.kVK_ANSI_R:
|
||||||
|
return key.CodeR
|
||||||
|
case C.kVK_ANSI_S:
|
||||||
|
return key.CodeS
|
||||||
|
case C.kVK_ANSI_T:
|
||||||
|
return key.CodeT
|
||||||
|
case C.kVK_ANSI_U:
|
||||||
|
return key.CodeU
|
||||||
|
case C.kVK_ANSI_V:
|
||||||
|
return key.CodeV
|
||||||
|
case C.kVK_ANSI_W:
|
||||||
|
return key.CodeW
|
||||||
|
case C.kVK_ANSI_X:
|
||||||
|
return key.CodeX
|
||||||
|
case C.kVK_ANSI_Y:
|
||||||
|
return key.CodeY
|
||||||
|
case C.kVK_ANSI_Z:
|
||||||
|
return key.CodeZ
|
||||||
|
case C.kVK_ANSI_1:
|
||||||
|
return key.Code1
|
||||||
|
case C.kVK_ANSI_2:
|
||||||
|
return key.Code2
|
||||||
|
case C.kVK_ANSI_3:
|
||||||
|
return key.Code3
|
||||||
|
case C.kVK_ANSI_4:
|
||||||
|
return key.Code4
|
||||||
|
case C.kVK_ANSI_5:
|
||||||
|
return key.Code5
|
||||||
|
case C.kVK_ANSI_6:
|
||||||
|
return key.Code6
|
||||||
|
case C.kVK_ANSI_7:
|
||||||
|
return key.Code7
|
||||||
|
case C.kVK_ANSI_8:
|
||||||
|
return key.Code8
|
||||||
|
case C.kVK_ANSI_9:
|
||||||
|
return key.Code9
|
||||||
|
case C.kVK_ANSI_0:
|
||||||
|
return key.Code0
|
||||||
|
// TODO: move the rest of these codes to constants in key.go
|
||||||
|
// if we are happy with them.
|
||||||
|
case C.kVK_Return:
|
||||||
|
return key.CodeReturnEnter
|
||||||
|
case C.kVK_Escape:
|
||||||
|
return key.CodeEscape
|
||||||
|
case C.kVK_Delete:
|
||||||
|
return key.CodeDeleteBackspace
|
||||||
|
case C.kVK_Tab:
|
||||||
|
return key.CodeTab
|
||||||
|
case C.kVK_Space:
|
||||||
|
return key.CodeSpacebar
|
||||||
|
case C.kVK_ANSI_Minus:
|
||||||
|
return key.CodeHyphenMinus
|
||||||
|
case C.kVK_ANSI_Equal:
|
||||||
|
return key.CodeEqualSign
|
||||||
|
case C.kVK_ANSI_LeftBracket:
|
||||||
|
return key.CodeLeftSquareBracket
|
||||||
|
case C.kVK_ANSI_RightBracket:
|
||||||
|
return key.CodeRightSquareBracket
|
||||||
|
case C.kVK_ANSI_Backslash:
|
||||||
|
return key.CodeBackslash
|
||||||
|
// 50: Keyboard Non-US "#" and ~
|
||||||
|
case C.kVK_ANSI_Semicolon:
|
||||||
|
return key.CodeSemicolon
|
||||||
|
case C.kVK_ANSI_Quote:
|
||||||
|
return key.CodeApostrophe
|
||||||
|
case C.kVK_ANSI_Grave:
|
||||||
|
return key.CodeGraveAccent
|
||||||
|
case C.kVK_ANSI_Comma:
|
||||||
|
return key.CodeComma
|
||||||
|
case C.kVK_ANSI_Period:
|
||||||
|
return key.CodeFullStop
|
||||||
|
case C.kVK_ANSI_Slash:
|
||||||
|
return key.CodeSlash
|
||||||
|
case C.kVK_CapsLock:
|
||||||
|
return key.CodeCapsLock
|
||||||
|
case C.kVK_F1:
|
||||||
|
return key.CodeF1
|
||||||
|
case C.kVK_F2:
|
||||||
|
return key.CodeF2
|
||||||
|
case C.kVK_F3:
|
||||||
|
return key.CodeF3
|
||||||
|
case C.kVK_F4:
|
||||||
|
return key.CodeF4
|
||||||
|
case C.kVK_F5:
|
||||||
|
return key.CodeF5
|
||||||
|
case C.kVK_F6:
|
||||||
|
return key.CodeF6
|
||||||
|
case C.kVK_F7:
|
||||||
|
return key.CodeF7
|
||||||
|
case C.kVK_F8:
|
||||||
|
return key.CodeF8
|
||||||
|
case C.kVK_F9:
|
||||||
|
return key.CodeF9
|
||||||
|
case C.kVK_F10:
|
||||||
|
return key.CodeF10
|
||||||
|
case C.kVK_F11:
|
||||||
|
return key.CodeF11
|
||||||
|
case C.kVK_F12:
|
||||||
|
return key.CodeF12
|
||||||
|
// 70: PrintScreen
|
||||||
|
// 71: Scroll Lock
|
||||||
|
// 72: Pause
|
||||||
|
// 73: Insert
|
||||||
|
case C.kVK_Home:
|
||||||
|
return key.CodeHome
|
||||||
|
case C.kVK_PageUp:
|
||||||
|
return key.CodePageUp
|
||||||
|
case C.kVK_ForwardDelete:
|
||||||
|
return key.CodeDeleteForward
|
||||||
|
case C.kVK_End:
|
||||||
|
return key.CodeEnd
|
||||||
|
case C.kVK_PageDown:
|
||||||
|
return key.CodePageDown
|
||||||
|
case C.kVK_RightArrow:
|
||||||
|
return key.CodeRightArrow
|
||||||
|
case C.kVK_LeftArrow:
|
||||||
|
return key.CodeLeftArrow
|
||||||
|
case C.kVK_DownArrow:
|
||||||
|
return key.CodeDownArrow
|
||||||
|
case C.kVK_UpArrow:
|
||||||
|
return key.CodeUpArrow
|
||||||
|
case C.kVK_ANSI_KeypadClear:
|
||||||
|
return key.CodeKeypadNumLock
|
||||||
|
case C.kVK_ANSI_KeypadDivide:
|
||||||
|
return key.CodeKeypadSlash
|
||||||
|
case C.kVK_ANSI_KeypadMultiply:
|
||||||
|
return key.CodeKeypadAsterisk
|
||||||
|
case C.kVK_ANSI_KeypadMinus:
|
||||||
|
return key.CodeKeypadHyphenMinus
|
||||||
|
case C.kVK_ANSI_KeypadPlus:
|
||||||
|
return key.CodeKeypadPlusSign
|
||||||
|
case C.kVK_ANSI_KeypadEnter:
|
||||||
|
return key.CodeKeypadEnter
|
||||||
|
case C.kVK_ANSI_Keypad1:
|
||||||
|
return key.CodeKeypad1
|
||||||
|
case C.kVK_ANSI_Keypad2:
|
||||||
|
return key.CodeKeypad2
|
||||||
|
case C.kVK_ANSI_Keypad3:
|
||||||
|
return key.CodeKeypad3
|
||||||
|
case C.kVK_ANSI_Keypad4:
|
||||||
|
return key.CodeKeypad4
|
||||||
|
case C.kVK_ANSI_Keypad5:
|
||||||
|
return key.CodeKeypad5
|
||||||
|
case C.kVK_ANSI_Keypad6:
|
||||||
|
return key.CodeKeypad6
|
||||||
|
case C.kVK_ANSI_Keypad7:
|
||||||
|
return key.CodeKeypad7
|
||||||
|
case C.kVK_ANSI_Keypad8:
|
||||||
|
return key.CodeKeypad8
|
||||||
|
case C.kVK_ANSI_Keypad9:
|
||||||
|
return key.CodeKeypad9
|
||||||
|
case C.kVK_ANSI_Keypad0:
|
||||||
|
return key.CodeKeypad0
|
||||||
|
case C.kVK_ANSI_KeypadDecimal:
|
||||||
|
return key.CodeKeypadFullStop
|
||||||
|
case C.kVK_ANSI_KeypadEquals:
|
||||||
|
return key.CodeKeypadEqualSign
|
||||||
|
case C.kVK_F13:
|
||||||
|
return key.CodeF13
|
||||||
|
case C.kVK_F14:
|
||||||
|
return key.CodeF14
|
||||||
|
case C.kVK_F15:
|
||||||
|
return key.CodeF15
|
||||||
|
case C.kVK_F16:
|
||||||
|
return key.CodeF16
|
||||||
|
case C.kVK_F17:
|
||||||
|
return key.CodeF17
|
||||||
|
case C.kVK_F18:
|
||||||
|
return key.CodeF18
|
||||||
|
case C.kVK_F19:
|
||||||
|
return key.CodeF19
|
||||||
|
case C.kVK_F20:
|
||||||
|
return key.CodeF20
|
||||||
|
// 116: Keyboard Execute
|
||||||
|
case C.kVK_Help:
|
||||||
|
return key.CodeHelp
|
||||||
|
// 118: Keyboard Menu
|
||||||
|
// 119: Keyboard Select
|
||||||
|
// 120: Keyboard Stop
|
||||||
|
// 121: Keyboard Again
|
||||||
|
// 122: Keyboard Undo
|
||||||
|
// 123: Keyboard Cut
|
||||||
|
// 124: Keyboard Copy
|
||||||
|
// 125: Keyboard Paste
|
||||||
|
// 126: Keyboard Find
|
||||||
|
case C.kVK_Mute:
|
||||||
|
return key.CodeMute
|
||||||
|
case C.kVK_VolumeUp:
|
||||||
|
return key.CodeVolumeUp
|
||||||
|
case C.kVK_VolumeDown:
|
||||||
|
return key.CodeVolumeDown
|
||||||
|
// 130: Keyboard Locking Caps Lock
|
||||||
|
// 131: Keyboard Locking Num Lock
|
||||||
|
// 132: Keyboard Locking Scroll Lock
|
||||||
|
// 133: Keyboard Comma
|
||||||
|
// 134: Keyboard Equal Sign
|
||||||
|
// ...: Bunch of stuff
|
||||||
|
case C.kVK_Control:
|
||||||
|
return key.CodeLeftControl
|
||||||
|
case C.kVK_Shift:
|
||||||
|
return key.CodeLeftShift
|
||||||
|
case C.kVK_Option:
|
||||||
|
return key.CodeLeftAlt
|
||||||
|
case C.kVK_Command:
|
||||||
|
return key.CodeLeftGUI
|
||||||
|
case C.kVK_RightControl:
|
||||||
|
return key.CodeRightControl
|
||||||
|
case C.kVK_RightShift:
|
||||||
|
return key.CodeRightShift
|
||||||
|
case C.kVK_RightOption:
|
||||||
|
return key.CodeRightAlt
|
||||||
|
// TODO key.CodeRightGUI
|
||||||
|
default:
|
||||||
|
return key.CodeUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
+251
@@ -0,0 +1,251 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin && !ios
|
||||||
|
// +build darwin
|
||||||
|
// +build !ios
|
||||||
|
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <OpenGL/gl3.h>
|
||||||
|
|
||||||
|
void makeCurrentContext(GLintptr context) {
|
||||||
|
NSOpenGLContext* ctx = (NSOpenGLContext*)context;
|
||||||
|
[ctx makeCurrentContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 threadID() {
|
||||||
|
uint64 id;
|
||||||
|
if (pthread_threadid_np(pthread_self(), &id)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface MobileGLView : NSOpenGLView<NSApplicationDelegate, NSWindowDelegate>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MobileGLView
|
||||||
|
- (void)prepareOpenGL {
|
||||||
|
[super prepareOpenGL];
|
||||||
|
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||||
|
GLint swapInt = 1;
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
GLuint vba;
|
||||||
|
glGenVertexArrays(1, &vba);
|
||||||
|
glBindVertexArray(vba);
|
||||||
|
|
||||||
|
startloop((GLintptr)[self openGLContext]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reshape {
|
||||||
|
[super reshape];
|
||||||
|
|
||||||
|
// Calculate screen PPI.
|
||||||
|
//
|
||||||
|
// Note that the backingScaleFactor converts from logical
|
||||||
|
// pixels to actual pixels, but both of these units vary
|
||||||
|
// independently from real world size. E.g.
|
||||||
|
//
|
||||||
|
// 13" Retina Macbook Pro, 2560x1600, 227ppi, backingScaleFactor=2, scale=3.15
|
||||||
|
// 15" Retina Macbook Pro, 2880x1800, 220ppi, backingScaleFactor=2, scale=3.06
|
||||||
|
// 27" iMac, 2560x1440, 109ppi, backingScaleFactor=1, scale=1.51
|
||||||
|
// 27" Retina iMac, 5120x2880, 218ppi, backingScaleFactor=2, scale=3.03
|
||||||
|
NSScreen *screen = [NSScreen mainScreen];
|
||||||
|
double screenPixW = [screen frame].size.width * [screen backingScaleFactor];
|
||||||
|
|
||||||
|
CGDirectDisplayID display = (CGDirectDisplayID)[[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue];
|
||||||
|
CGSize screenSizeMM = CGDisplayScreenSize(display); // in millimeters
|
||||||
|
float ppi = 25.4 * screenPixW / screenSizeMM.width;
|
||||||
|
float pixelsPerPt = ppi/72.0;
|
||||||
|
|
||||||
|
// The width and height reported to the geom package are the
|
||||||
|
// bounds of the OpenGL view. Several steps are necessary.
|
||||||
|
// First, [self bounds] gives us the number of logical pixels
|
||||||
|
// in the view. Multiplying this by the backingScaleFactor
|
||||||
|
// gives us the number of actual pixels.
|
||||||
|
NSRect r = [self bounds];
|
||||||
|
int w = r.size.width * [screen backingScaleFactor];
|
||||||
|
int h = r.size.height * [screen backingScaleFactor];
|
||||||
|
|
||||||
|
setGeom(pixelsPerPt, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(NSRect)theRect {
|
||||||
|
// Called during resize. This gets rid of flicker when resizing.
|
||||||
|
drawgl();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent *)theEvent {
|
||||||
|
double scale = [[NSScreen mainScreen] backingScaleFactor];
|
||||||
|
NSPoint p = [theEvent locationInWindow];
|
||||||
|
eventMouseDown(p.x * scale, p.y * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(NSEvent *)theEvent {
|
||||||
|
double scale = [[NSScreen mainScreen] backingScaleFactor];
|
||||||
|
NSPoint p = [theEvent locationInWindow];
|
||||||
|
eventMouseEnd(p.x * scale, p.y * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(NSEvent *)theEvent {
|
||||||
|
double scale = [[NSScreen mainScreen] backingScaleFactor];
|
||||||
|
NSPoint p = [theEvent locationInWindow];
|
||||||
|
eventMouseDragged(p.x * scale, p.y * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||||
|
lifecycleFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResignKey:(NSNotification *)notification {
|
||||||
|
if (![NSApp isHidden]) {
|
||||||
|
lifecycleVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
|
lifecycleAlive();
|
||||||
|
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||||
|
[self.window makeKeyAndOrderFront:self];
|
||||||
|
lifecycleVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||||
|
lifecycleDead();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidHide:(NSNotification *)aNotification {
|
||||||
|
lifecycleAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillUnhide:(NSNotification *)notification {
|
||||||
|
lifecycleVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillClose:(NSNotification *)notification {
|
||||||
|
lifecycleAlive();
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MobileResponder : NSResponder
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MobileResponder
|
||||||
|
- (void)keyDown:(NSEvent *)theEvent {
|
||||||
|
[self key:theEvent];
|
||||||
|
}
|
||||||
|
- (void)keyUp:(NSEvent *)theEvent {
|
||||||
|
[self key:theEvent];
|
||||||
|
}
|
||||||
|
- (void)key:(NSEvent *)theEvent {
|
||||||
|
NSRange range = [theEvent.characters rangeOfComposedCharacterSequenceAtIndex:0];
|
||||||
|
|
||||||
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
|
if (![theEvent.characters getBytes:buf
|
||||||
|
maxLength:4
|
||||||
|
usedLength:nil
|
||||||
|
encoding:NSUTF32LittleEndianStringEncoding
|
||||||
|
options:NSStringEncodingConversionAllowLossy
|
||||||
|
range:range
|
||||||
|
remainingRange:nil]) {
|
||||||
|
NSLog(@"failed to read key event %@", theEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rune = (uint32_t)buf[0]<<0 | (uint32_t)buf[1]<<8 | (uint32_t)buf[2]<<16 | (uint32_t)buf[3]<<24;
|
||||||
|
|
||||||
|
uint8_t direction;
|
||||||
|
if ([theEvent isARepeat]) {
|
||||||
|
direction = 0;
|
||||||
|
} else if (theEvent.type == NSEventTypeKeyDown) {
|
||||||
|
direction = 1;
|
||||||
|
} else {
|
||||||
|
direction = 2;
|
||||||
|
}
|
||||||
|
eventKey((int32_t)rune, direction, theEvent.keyCode, theEvent.modifierFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)flagsChanged:(NSEvent *)theEvent {
|
||||||
|
eventFlags(theEvent.modifierFlags);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
void
|
||||||
|
runApp(void) {
|
||||||
|
[NSAutoreleasePool new];
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
|
||||||
|
id menuBar = [[NSMenu new] autorelease];
|
||||||
|
id menuItem = [[NSMenuItem new] autorelease];
|
||||||
|
[menuBar addItem:menuItem];
|
||||||
|
[NSApp setMainMenu:menuBar];
|
||||||
|
|
||||||
|
id menu = [[NSMenu new] autorelease];
|
||||||
|
id name = [[NSProcessInfo processInfo] processName];
|
||||||
|
|
||||||
|
id hideMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Hide"
|
||||||
|
action:@selector(hide:) keyEquivalent:@"h"]
|
||||||
|
autorelease];
|
||||||
|
[menu addItem:hideMenuItem];
|
||||||
|
|
||||||
|
id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
|
||||||
|
action:@selector(terminate:) keyEquivalent:@"q"]
|
||||||
|
autorelease];
|
||||||
|
[menu addItem:quitMenuItem];
|
||||||
|
[menuItem setSubmenu:menu];
|
||||||
|
|
||||||
|
NSRect rect = NSMakeRect(0, 0, 600, 800);
|
||||||
|
|
||||||
|
NSWindow* window = [[[NSWindow alloc] initWithContentRect:rect
|
||||||
|
styleMask:NSWindowStyleMaskTitled
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:NO]
|
||||||
|
autorelease];
|
||||||
|
window.styleMask |= NSWindowStyleMaskResizable;
|
||||||
|
window.styleMask |= NSWindowStyleMaskMiniaturizable;
|
||||||
|
window.styleMask |= NSWindowStyleMaskClosable;
|
||||||
|
window.title = name;
|
||||||
|
[window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
|
||||||
|
|
||||||
|
NSOpenGLPixelFormatAttribute attr[] = {
|
||||||
|
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||||
|
NSOpenGLPFAColorSize, 24,
|
||||||
|
NSOpenGLPFAAlphaSize, 8,
|
||||||
|
NSOpenGLPFADepthSize, 16,
|
||||||
|
NSOpenGLPFAAccelerated,
|
||||||
|
NSOpenGLPFADoubleBuffer,
|
||||||
|
NSOpenGLPFAAllowOfflineRenderers,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
|
||||||
|
MobileGLView* view = [[MobileGLView alloc] initWithFrame:rect pixelFormat:pixFormat];
|
||||||
|
[window setContentView:view];
|
||||||
|
[window setDelegate:view];
|
||||||
|
[NSApp setDelegate:view];
|
||||||
|
|
||||||
|
window.nextResponder = [[[MobileResponder alloc] init] autorelease];
|
||||||
|
|
||||||
|
[NSApp run];
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopApp(void) {
|
||||||
|
[NSApp terminate:nil];
|
||||||
|
}
|
||||||
+215
@@ -0,0 +1,215 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin && ios
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c -DGL_SILENCE_DEPRECATION -DGLES_SILENCE_DEPRECATION
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework UIKit -framework GLKit -framework OpenGLES -framework QuartzCore
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <UIKit/UIDevice.h>
|
||||||
|
#import <GLKit/GLKit.h>
|
||||||
|
|
||||||
|
extern struct utsname sysInfo;
|
||||||
|
|
||||||
|
void runApp(void);
|
||||||
|
void makeCurrentContext(GLintptr ctx);
|
||||||
|
void swapBuffers(GLintptr ctx);
|
||||||
|
uint64_t threadID();
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/paint"
|
||||||
|
"github.com/ebitengine/gomobile/event/size"
|
||||||
|
"github.com/ebitengine/gomobile/event/touch"
|
||||||
|
"github.com/ebitengine/gomobile/geom"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 UIKit 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 main(f func(App)) {
|
||||||
|
if tid := uint64(C.threadID()); tid != initThreadID {
|
||||||
|
log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
f(theApp)
|
||||||
|
// TODO(crawshaw): trigger runApp to return
|
||||||
|
}()
|
||||||
|
C.runApp()
|
||||||
|
panic("unexpected return from app.runApp")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pixelsPerPt float32
|
||||||
|
var screenScale int // [UIScreen mainScreen].scale, either 1, 2, or 3.
|
||||||
|
|
||||||
|
//export setScreen
|
||||||
|
func setScreen(scale int) {
|
||||||
|
C.uname(&C.sysInfo)
|
||||||
|
name := C.GoString(&C.sysInfo.machine[0])
|
||||||
|
|
||||||
|
var v float32
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(name, "iPhone"):
|
||||||
|
v = 163
|
||||||
|
case strings.HasPrefix(name, "iPad"):
|
||||||
|
// TODO: is there a better way to distinguish the iPad Mini?
|
||||||
|
switch name {
|
||||||
|
case "iPad2,5", "iPad2,6", "iPad2,7", "iPad4,4", "iPad4,5", "iPad4,6", "iPad4,7":
|
||||||
|
v = 163 // iPad Mini
|
||||||
|
default:
|
||||||
|
v = 132
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
v = 163 // names like i386 and x86_64 are the simulator
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == 0 {
|
||||||
|
log.Printf("unknown machine: %s", name)
|
||||||
|
v = 163 // emergency fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelsPerPt = v * float32(scale) / 72
|
||||||
|
screenScale = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
//export updateConfig
|
||||||
|
func updateConfig(width, height, orientation int32) {
|
||||||
|
o := size.OrientationUnknown
|
||||||
|
switch orientation {
|
||||||
|
case C.UIDeviceOrientationPortrait, C.UIDeviceOrientationPortraitUpsideDown:
|
||||||
|
o = size.OrientationPortrait
|
||||||
|
case C.UIDeviceOrientationLandscapeLeft, C.UIDeviceOrientationLandscapeRight:
|
||||||
|
o = size.OrientationLandscape
|
||||||
|
}
|
||||||
|
widthPx := screenScale * int(width)
|
||||||
|
heightPx := screenScale * int(height)
|
||||||
|
theApp.eventsIn <- size.Event{
|
||||||
|
WidthPx: widthPx,
|
||||||
|
HeightPx: heightPx,
|
||||||
|
WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt),
|
||||||
|
HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt),
|
||||||
|
PixelsPerPt: pixelsPerPt,
|
||||||
|
Orientation: o,
|
||||||
|
}
|
||||||
|
theApp.eventsIn <- paint.Event{External: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// touchIDs is the current active touches. The position in the array
|
||||||
|
// is the ID, the value is the UITouch* pointer value.
|
||||||
|
//
|
||||||
|
// It is widely reported that the iPhone can handle up to 5 simultaneous
|
||||||
|
// touch events, while the iPad can handle 11.
|
||||||
|
var touchIDs [11]uintptr
|
||||||
|
|
||||||
|
var touchEvents struct {
|
||||||
|
sync.Mutex
|
||||||
|
pending []touch.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
//export sendTouch
|
||||||
|
func sendTouch(cTouch, cTouchType uintptr, x, y float32) {
|
||||||
|
id := -1
|
||||||
|
for i, val := range touchIDs {
|
||||||
|
if val == cTouch {
|
||||||
|
id = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if id == -1 {
|
||||||
|
for i, val := range touchIDs {
|
||||||
|
if val == 0 {
|
||||||
|
touchIDs[i] = cTouch
|
||||||
|
id = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if id == -1 {
|
||||||
|
panic("out of touchIDs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t := touch.Type(cTouchType)
|
||||||
|
if t == touch.TypeEnd {
|
||||||
|
touchIDs[id] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
theApp.eventsIn <- touch.Event{
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
Sequence: touch.Sequence(id),
|
||||||
|
Type: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export lifecycleDead
|
||||||
|
func lifecycleDead() { theApp.sendLifecycle(lifecycle.StageDead) }
|
||||||
|
|
||||||
|
//export lifecycleAlive
|
||||||
|
func lifecycleAlive() { theApp.sendLifecycle(lifecycle.StageAlive) }
|
||||||
|
|
||||||
|
//export lifecycleVisible
|
||||||
|
func lifecycleVisible() { theApp.sendLifecycle(lifecycle.StageVisible) }
|
||||||
|
|
||||||
|
//export lifecycleFocused
|
||||||
|
func lifecycleFocused() { theApp.sendLifecycle(lifecycle.StageFocused) }
|
||||||
|
|
||||||
|
//export startloop
|
||||||
|
func startloop(ctx C.GLintptr) {
|
||||||
|
go theApp.loop(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop is the primary drawing loop.
|
||||||
|
//
|
||||||
|
// After UIKit has captured the initial OS thread for processing UIKit
|
||||||
|
// events in runApp, it starts loop on another goroutine. It is locked
|
||||||
|
// to an OS thread for its OpenGL context.
|
||||||
|
func (a *app) loop(ctx C.GLintptr) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
C.makeCurrentContext(ctx)
|
||||||
|
|
||||||
|
workAvailable := a.worker.WorkAvailable()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-workAvailable:
|
||||||
|
a.worker.DoWork()
|
||||||
|
case <-theApp.publish:
|
||||||
|
loop1:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-workAvailable:
|
||||||
|
a.worker.DoWork()
|
||||||
|
default:
|
||||||
|
break loop1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C.swapBuffers(ctx)
|
||||||
|
theApp.publishResult <- PublishResult{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin && ios
|
||||||
|
// +build darwin
|
||||||
|
// +build ios
|
||||||
|
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <GLKit/GLKit.h>
|
||||||
|
|
||||||
|
struct utsname sysInfo;
|
||||||
|
|
||||||
|
@interface GoAppAppController : GLKViewController<UIContentContainer, GLKViewDelegate>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface GoAppAppDelegate : UIResponder<UIApplicationDelegate>
|
||||||
|
@property (strong, nonatomic) UIWindow *window;
|
||||||
|
@property (strong, nonatomic) GoAppAppController *controller;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GoAppAppDelegate
|
||||||
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
lifecycleAlive();
|
||||||
|
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||||
|
self.controller = [[GoAppAppController alloc] initWithNibName:nil bundle:nil];
|
||||||
|
self.window.rootViewController = self.controller;
|
||||||
|
[self.window makeKeyAndVisible];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(UIApplication * )application {
|
||||||
|
lifecycleFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||||
|
lifecycleVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||||
|
lifecycleAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||||
|
lifecycleDead();
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface GoAppAppController ()
|
||||||
|
@property (strong, nonatomic) EAGLContext *context;
|
||||||
|
@property (strong, nonatomic) GLKView *glview;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GoAppAppController
|
||||||
|
- (void)viewWillAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
// TODO: replace by swapping out GLKViewController for a UIVIewController.
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
self.paused = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||||
|
self.glview = (GLKView*)self.view;
|
||||||
|
self.glview.drawableDepthFormat = GLKViewDrawableDepthFormat24;
|
||||||
|
self.glview.multipleTouchEnabled = true; // TODO expose setting to user.
|
||||||
|
self.glview.context = self.context;
|
||||||
|
self.glview.userInteractionEnabled = YES;
|
||||||
|
self.glview.enableSetNeedsDisplay = YES; // only invoked once
|
||||||
|
|
||||||
|
// Do not use the GLKViewController draw loop.
|
||||||
|
self.paused = YES;
|
||||||
|
self.resumeOnDidBecomeActive = NO;
|
||||||
|
self.preferredFramesPerSecond = 0;
|
||||||
|
|
||||||
|
int scale = 1;
|
||||||
|
if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) {
|
||||||
|
scale = (int)[UIScreen mainScreen].scale; // either 1.0, 2.0, or 3.0.
|
||||||
|
}
|
||||||
|
setScreen(scale);
|
||||||
|
|
||||||
|
CGSize size = [UIScreen mainScreen].bounds.size;
|
||||||
|
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
|
||||||
|
updateConfig((int)size.width, (int)size.height, orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||||
|
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||||
|
// TODO(crawshaw): come up with a plan to handle animations.
|
||||||
|
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||||
|
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
|
||||||
|
updateConfig((int)size.width, (int)size.height, orientation);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
|
||||||
|
// Now that we have been asked to do the first draw, disable any
|
||||||
|
// future draw and hand control over to the Go paint.Event cycle.
|
||||||
|
self.glview.enableSetNeedsDisplay = NO;
|
||||||
|
startloop((GLintptr)self.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TOUCH_TYPE_BEGIN 0 // touch.TypeBegin
|
||||||
|
#define TOUCH_TYPE_MOVE 1 // touch.TypeMove
|
||||||
|
#define TOUCH_TYPE_END 2 // touch.TypeEnd
|
||||||
|
|
||||||
|
static void sendTouches(int change, NSSet* touches) {
|
||||||
|
CGFloat scale = [UIScreen mainScreen].scale;
|
||||||
|
for (UITouch* touch in touches) {
|
||||||
|
CGPoint p = [touch locationInView:touch.view];
|
||||||
|
sendTouch((GoUintptr)touch, (GoUintptr)change, p.x*scale, p.y*scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||||
|
sendTouches(TOUCH_TYPE_BEGIN, touches);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||||
|
sendTouches(TOUCH_TYPE_MOVE, touches);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||||
|
sendTouches(TOUCH_TYPE_END, touches);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesCanceled:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||||
|
sendTouches(TOUCH_TYPE_END, touches);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
void runApp(void) {
|
||||||
|
char* argv[] = {};
|
||||||
|
@autoreleasepool {
|
||||||
|
UIApplicationMain(0, argv, nil, NSStringFromClass([GoAppAppDelegate class]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeCurrentContext(GLintptr context) {
|
||||||
|
EAGLContext* ctx = (EAGLContext*)context;
|
||||||
|
if (![EAGLContext setCurrentContext:ctx]) {
|
||||||
|
// TODO(crawshaw): determine how terrible this is. Exit?
|
||||||
|
NSLog(@"failed to set current context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapBuffers(GLintptr context) {
|
||||||
|
__block EAGLContext* ctx = (EAGLContext*)context;
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
|
[EAGLContext setCurrentContext:ctx];
|
||||||
|
[ctx presentRenderbuffer:GL_RENDERBUFFER];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t threadID() {
|
||||||
|
uint64_t id;
|
||||||
|
if (pthread_threadid_np(pthread_self(), &id)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package app lets you write portable all-Go apps for Android and iOS.
|
||||||
|
|
||||||
|
There are typically two ways to use Go on Android and iOS. The first
|
||||||
|
is to write a Go library and use `gomobile bind` to generate language
|
||||||
|
bindings for Java and Objective-C. Building a library does not
|
||||||
|
require the app package. The `gomobile bind` command produces output
|
||||||
|
that you can include in an Android Studio or Xcode project. For more
|
||||||
|
on language bindings, see https://github.com/ebitengine/gomobile/cmd/gobind.
|
||||||
|
|
||||||
|
The second way is to write an app entirely in Go. The APIs are limited
|
||||||
|
to those that are portable between both Android and iOS, in particular
|
||||||
|
OpenGL, audio, and other Android NDK-like APIs. An all-Go app should
|
||||||
|
use this app package to initialize the app, manage its lifecycle, and
|
||||||
|
receive events.
|
||||||
|
|
||||||
|
# Building apps
|
||||||
|
|
||||||
|
Apps written entirely in Go have a main function, and can be built
|
||||||
|
with `gomobile build`, which directly produces runnable output for
|
||||||
|
Android and iOS.
|
||||||
|
|
||||||
|
The gomobile tool can get installed with go get. For reference, see
|
||||||
|
https://github.com/ebitengine/gomobile/cmd/gomobile.
|
||||||
|
|
||||||
|
For detailed instructions and documentation, see
|
||||||
|
https://golang.org/wiki/Mobile.
|
||||||
|
|
||||||
|
# Event processing in Native Apps
|
||||||
|
|
||||||
|
The Go runtime is initialized on Android when NativeActivity onCreate is
|
||||||
|
called, and on iOS when the process starts. In both cases, Go init functions
|
||||||
|
run before the app lifecycle has started.
|
||||||
|
|
||||||
|
An app is expected to call the Main function in main.main. When the function
|
||||||
|
exits, the app exits. Inside the func passed to Main, call Filter on every
|
||||||
|
event received, and then switch on its type. Registered filters run when the
|
||||||
|
event is received, not when it is sent, so that filters run in the same
|
||||||
|
goroutine as other code that calls OpenGL.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/app"
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/paint"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app.Main(func(a app.App) {
|
||||||
|
for e := range a.Events() {
|
||||||
|
switch e := a.Filter(e).(type) {
|
||||||
|
case lifecycle.Event:
|
||||||
|
// ...
|
||||||
|
case paint.Event:
|
||||||
|
log.Print("Call OpenGL here.")
|
||||||
|
a.Publish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
An event is represented by the empty interface type interface{}. Any value can
|
||||||
|
be an event. Commonly used types include Event types defined by the following
|
||||||
|
packages:
|
||||||
|
- github.com/ebitengine/gomobile/event/lifecycle
|
||||||
|
- github.com/ebitengine/gomobile/event/mouse
|
||||||
|
- github.com/ebitengine/gomobile/event/paint
|
||||||
|
- github.com/ebitengine/gomobile/event/size
|
||||||
|
- github.com/ebitengine/gomobile/event/touch
|
||||||
|
|
||||||
|
For example, touch.Event is the type that represents touch events. Other
|
||||||
|
packages may define their own events, and send them on an app's event channel.
|
||||||
|
|
||||||
|
Other packages can also register event filters, e.g. to manage resources in
|
||||||
|
response to lifecycle events. Such packages should call:
|
||||||
|
|
||||||
|
app.RegisterFilter(etc)
|
||||||
|
|
||||||
|
in an init function inside that package.
|
||||||
|
*/
|
||||||
|
package app // import "github.com/ebitengine/gomobile/app"
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build android && (arm || 386 || amd64 || arm64)
|
||||||
|
|
||||||
|
// Package callfn provides an android entry point.
|
||||||
|
//
|
||||||
|
// It is a separate package from app because it contains Go assembly,
|
||||||
|
// which does not compile in a package using cgo.
|
||||||
|
package callfn
|
||||||
|
|
||||||
|
// CallFn calls a zero-argument function by its program counter.
|
||||||
|
// It is only intended for calling main.main. Using it for
|
||||||
|
// anything else will not end well.
|
||||||
|
func CallFn(fn uintptr)
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 "textflag.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
|
TEXT ·CallFn(SB),$0-4
|
||||||
|
MOVL fn+0(FP), AX
|
||||||
|
CALL AX
|
||||||
|
RET
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 "textflag.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
|
TEXT ·CallFn(SB),$0-8
|
||||||
|
MOVQ fn+0(FP), AX
|
||||||
|
CALL AX
|
||||||
|
RET
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 "textflag.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
|
TEXT ·CallFn(SB),$0-4
|
||||||
|
MOVW fn+0(FP), R0
|
||||||
|
BL (R0)
|
||||||
|
RET
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2016 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 "textflag.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
|
TEXT ·CallFn(SB),$0-8
|
||||||
|
MOVD fn+0(FP), R0
|
||||||
|
BL (R0)
|
||||||
|
RET
|
||||||
+175
@@ -0,0 +1,175 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build linux && !android
|
||||||
|
// +build linux,!android
|
||||||
|
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static Atom wm_delete_window;
|
||||||
|
|
||||||
|
static Window
|
||||||
|
new_window(Display *x_dpy, EGLDisplay e_dpy, int w, int h, EGLContext *ctx, EGLSurface *surf) {
|
||||||
|
static const EGLint attribs[] = {
|
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_DEPTH_SIZE, 16,
|
||||||
|
EGL_CONFIG_CAVEAT, EGL_NONE,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
EGLConfig config;
|
||||||
|
EGLint num_configs;
|
||||||
|
if (!eglChooseConfig(e_dpy, attribs, &config, 1, &num_configs)) {
|
||||||
|
fprintf(stderr, "eglChooseConfig failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
EGLint vid;
|
||||||
|
if (!eglGetConfigAttrib(e_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
|
||||||
|
fprintf(stderr, "eglGetConfigAttrib failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XVisualInfo visTemplate;
|
||||||
|
visTemplate.visualid = vid;
|
||||||
|
int num_visuals;
|
||||||
|
XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
|
||||||
|
if (!visInfo) {
|
||||||
|
fprintf(stderr, "XGetVisualInfo failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Window root = RootWindow(x_dpy, DefaultScreen(x_dpy));
|
||||||
|
XSetWindowAttributes attr;
|
||||||
|
|
||||||
|
attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone);
|
||||||
|
if (!attr.colormap) {
|
||||||
|
fprintf(stderr, "XCreateColormap failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.event_mask = StructureNotifyMask | ExposureMask |
|
||||||
|
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;
|
||||||
|
Window win = XCreateWindow(
|
||||||
|
x_dpy, root, 0, 0, w, h, 0, visInfo->depth, InputOutput,
|
||||||
|
visInfo->visual, CWColormap | CWEventMask, &attr);
|
||||||
|
XFree(visInfo);
|
||||||
|
|
||||||
|
XSizeHints sizehints;
|
||||||
|
sizehints.width = w;
|
||||||
|
sizehints.height = h;
|
||||||
|
sizehints.flags = USSize;
|
||||||
|
XSetNormalHints(x_dpy, win, &sizehints);
|
||||||
|
XSetStandardProperties(x_dpy, win, "App", "App", None, (char **)NULL, 0, &sizehints);
|
||||||
|
|
||||||
|
static const EGLint ctx_attribs[] = {
|
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
*ctx = eglCreateContext(e_dpy, config, EGL_NO_CONTEXT, ctx_attribs);
|
||||||
|
if (!*ctx) {
|
||||||
|
fprintf(stderr, "eglCreateContext failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*surf = eglCreateWindowSurface(e_dpy, config, win, NULL);
|
||||||
|
if (!*surf) {
|
||||||
|
fprintf(stderr, "eglCreateWindowSurface failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
Display *x_dpy;
|
||||||
|
EGLDisplay e_dpy;
|
||||||
|
EGLContext e_ctx;
|
||||||
|
EGLSurface e_surf;
|
||||||
|
Window win;
|
||||||
|
|
||||||
|
void
|
||||||
|
createWindow(void) {
|
||||||
|
x_dpy = XOpenDisplay(NULL);
|
||||||
|
if (!x_dpy) {
|
||||||
|
fprintf(stderr, "XOpenDisplay failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
e_dpy = eglGetDisplay(x_dpy);
|
||||||
|
if (!e_dpy) {
|
||||||
|
fprintf(stderr, "eglGetDisplay failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
EGLint e_major, e_minor;
|
||||||
|
if (!eglInitialize(e_dpy, &e_major, &e_minor)) {
|
||||||
|
fprintf(stderr, "eglInitialize failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
win = new_window(x_dpy, e_dpy, 600, 800, &e_ctx, &e_surf);
|
||||||
|
|
||||||
|
wm_delete_window = XInternAtom(x_dpy, "WM_DELETE_WINDOW", True);
|
||||||
|
if (wm_delete_window != None) {
|
||||||
|
XSetWMProtocols(x_dpy, win, &wm_delete_window, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMapWindow(x_dpy, win);
|
||||||
|
if (!eglMakeCurrent(e_dpy, e_surf, e_surf, e_ctx)) {
|
||||||
|
fprintf(stderr, "eglMakeCurrent failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window size and DPI should be initialized before starting app.
|
||||||
|
XEvent ev;
|
||||||
|
while (1) {
|
||||||
|
if (XCheckMaskEvent(x_dpy, StructureNotifyMask, &ev) == False) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ev.type == ConfigureNotify) {
|
||||||
|
onResize(ev.xconfigure.width, ev.xconfigure.height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
processEvents(void) {
|
||||||
|
while (XPending(x_dpy)) {
|
||||||
|
XEvent ev;
|
||||||
|
XNextEvent(x_dpy, &ev);
|
||||||
|
switch (ev.type) {
|
||||||
|
case ButtonPress:
|
||||||
|
onTouchBegin((float)ev.xbutton.x, (float)ev.xbutton.y);
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
onTouchEnd((float)ev.xbutton.x, (float)ev.xbutton.y);
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
onTouchMove((float)ev.xmotion.x, (float)ev.xmotion.y);
|
||||||
|
break;
|
||||||
|
case ConfigureNotify:
|
||||||
|
onResize(ev.xconfigure.width, ev.xconfigure.height);
|
||||||
|
break;
|
||||||
|
case ClientMessage:
|
||||||
|
if (wm_delete_window != None && (Atom)ev.xclient.data.l[0] == wm_delete_window) {
|
||||||
|
onStop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
swapBuffers(void) {
|
||||||
|
if (eglSwapBuffers(e_dpy, e_surf) == EGL_FALSE) {
|
||||||
|
fprintf(stderr, "eglSwapBuffer failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build linux && !android
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
/*
|
||||||
|
Simple on-screen app debugging for X11. Not an officially supported
|
||||||
|
development target for apps, as screens with mice are very different
|
||||||
|
than screens with touch panels.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -lEGL -lGLESv2 -lX11
|
||||||
|
|
||||||
|
void createWindow(void);
|
||||||
|
void processEvents(void);
|
||||||
|
void swapBuffers(void);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
"github.com/ebitengine/gomobile/event/paint"
|
||||||
|
"github.com/ebitengine/gomobile/event/size"
|
||||||
|
"github.com/ebitengine/gomobile/event/touch"
|
||||||
|
"github.com/ebitengine/gomobile/geom"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
theApp.registerGLViewportFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main(f func(App)) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
workAvailable := theApp.worker.WorkAvailable()
|
||||||
|
|
||||||
|
C.createWindow()
|
||||||
|
|
||||||
|
// TODO: send lifecycle events when e.g. the X11 window is iconified or moved off-screen.
|
||||||
|
theApp.sendLifecycle(lifecycle.StageFocused)
|
||||||
|
|
||||||
|
// TODO: translate X11 expose events to shiny paint events, instead of
|
||||||
|
// sending this synthetic paint event as a hack.
|
||||||
|
theApp.eventsIn <- paint.Event{}
|
||||||
|
|
||||||
|
donec := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
// close the donec channel in a defer statement
|
||||||
|
// so that we could still be able to return even
|
||||||
|
// if f panics.
|
||||||
|
defer close(donec)
|
||||||
|
|
||||||
|
f(theApp)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TODO: can we get the actual vsync signal?
|
||||||
|
ticker := time.NewTicker(time.Second / 60)
|
||||||
|
defer ticker.Stop()
|
||||||
|
var tc <-chan time.Time
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-donec:
|
||||||
|
return
|
||||||
|
case <-workAvailable:
|
||||||
|
theApp.worker.DoWork()
|
||||||
|
case <-theApp.publish:
|
||||||
|
C.swapBuffers()
|
||||||
|
tc = ticker.C
|
||||||
|
case <-tc:
|
||||||
|
tc = nil
|
||||||
|
theApp.publishResult <- PublishResult{}
|
||||||
|
}
|
||||||
|
C.processEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onResize
|
||||||
|
func onResize(w, h int) {
|
||||||
|
// TODO(nigeltao): don't assume 72 DPI. DisplayWidth and DisplayWidthMM
|
||||||
|
// is probably the best place to start looking.
|
||||||
|
pixelsPerPt := float32(1)
|
||||||
|
theApp.eventsIn <- size.Event{
|
||||||
|
WidthPx: w,
|
||||||
|
HeightPx: h,
|
||||||
|
WidthPt: geom.Pt(w),
|
||||||
|
HeightPt: geom.Pt(h),
|
||||||
|
PixelsPerPt: pixelsPerPt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendTouch(t touch.Type, x, y float32) {
|
||||||
|
theApp.eventsIn <- touch.Event{
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
Sequence: 0, // TODO: button??
|
||||||
|
Type: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export onTouchBegin
|
||||||
|
func onTouchBegin(x, y float32) { sendTouch(touch.TypeBegin, x, y) }
|
||||||
|
|
||||||
|
//export onTouchMove
|
||||||
|
func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) }
|
||||||
|
|
||||||
|
//export onTouchEnd
|
||||||
|
func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
|
||||||
|
|
||||||
|
var stopped bool
|
||||||
|
|
||||||
|
//export onStop
|
||||||
|
func onStop() {
|
||||||
|
if stopped {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stopped = true
|
||||||
|
theApp.sendLifecycle(lifecycle.StageDead)
|
||||||
|
theApp.eventsIn <- stopPumping{}
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
// Code generated by "stringer -type=Code"; DO NOT EDIT
|
||||||
|
|
||||||
|
package key
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const (
|
||||||
|
_Code_name_0 = "CodeUnknown"
|
||||||
|
_Code_name_1 = "CodeACodeBCodeCCodeDCodeECodeFCodeGCodeHCodeICodeJCodeKCodeLCodeMCodeNCodeOCodePCodeQCodeRCodeSCodeTCodeUCodeVCodeWCodeXCodeYCodeZCode1Code2Code3Code4Code5Code6Code7Code8Code9Code0CodeReturnEnterCodeEscapeCodeDeleteBackspaceCodeTabCodeSpacebarCodeHyphenMinusCodeEqualSignCodeLeftSquareBracketCodeRightSquareBracketCodeBackslash"
|
||||||
|
_Code_name_2 = "CodeSemicolonCodeApostropheCodeGraveAccentCodeCommaCodeFullStopCodeSlashCodeCapsLockCodeF1CodeF2CodeF3CodeF4CodeF5CodeF6CodeF7CodeF8CodeF9CodeF10CodeF11CodeF12"
|
||||||
|
_Code_name_3 = "CodePauseCodeInsertCodeHomeCodePageUpCodeDeleteForwardCodeEndCodePageDownCodeRightArrowCodeLeftArrowCodeDownArrowCodeUpArrowCodeKeypadNumLockCodeKeypadSlashCodeKeypadAsteriskCodeKeypadHyphenMinusCodeKeypadPlusSignCodeKeypadEnterCodeKeypad1CodeKeypad2CodeKeypad3CodeKeypad4CodeKeypad5CodeKeypad6CodeKeypad7CodeKeypad8CodeKeypad9CodeKeypad0CodeKeypadFullStop"
|
||||||
|
_Code_name_4 = "CodeKeypadEqualSignCodeF13CodeF14CodeF15CodeF16CodeF17CodeF18CodeF19CodeF20CodeF21CodeF22CodeF23CodeF24"
|
||||||
|
_Code_name_5 = "CodeHelp"
|
||||||
|
_Code_name_6 = "CodeMuteCodeVolumeUpCodeVolumeDown"
|
||||||
|
_Code_name_7 = "CodeLeftControlCodeLeftShiftCodeLeftAltCodeLeftGUICodeRightControlCodeRightShiftCodeRightAltCodeRightGUI"
|
||||||
|
_Code_name_8 = "CodeCompose"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_Code_index_0 = [...]uint8{0, 11}
|
||||||
|
_Code_index_1 = [...]uint16{0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, 180, 195, 205, 224, 231, 243, 258, 271, 292, 314, 327}
|
||||||
|
_Code_index_2 = [...]uint8{0, 13, 27, 42, 51, 63, 72, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 145, 152, 159}
|
||||||
|
_Code_index_3 = [...]uint16{0, 9, 19, 27, 37, 54, 61, 73, 87, 100, 113, 124, 141, 156, 174, 195, 213, 228, 239, 250, 261, 272, 283, 294, 305, 316, 327, 338, 356}
|
||||||
|
_Code_index_4 = [...]uint8{0, 19, 26, 33, 40, 47, 54, 61, 68, 75, 82, 89, 96, 103}
|
||||||
|
_Code_index_5 = [...]uint8{0, 8}
|
||||||
|
_Code_index_6 = [...]uint8{0, 8, 20, 34}
|
||||||
|
_Code_index_7 = [...]uint8{0, 15, 28, 39, 50, 66, 80, 92, 104}
|
||||||
|
_Code_index_8 = [...]uint8{0, 11}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i Code) String() string {
|
||||||
|
switch {
|
||||||
|
case i == 0:
|
||||||
|
return _Code_name_0
|
||||||
|
case 4 <= i && i <= 49:
|
||||||
|
i -= 4
|
||||||
|
return _Code_name_1[_Code_index_1[i]:_Code_index_1[i+1]]
|
||||||
|
case 51 <= i && i <= 69:
|
||||||
|
i -= 51
|
||||||
|
return _Code_name_2[_Code_index_2[i]:_Code_index_2[i+1]]
|
||||||
|
case 72 <= i && i <= 99:
|
||||||
|
i -= 72
|
||||||
|
return _Code_name_3[_Code_index_3[i]:_Code_index_3[i+1]]
|
||||||
|
case 103 <= i && i <= 115:
|
||||||
|
i -= 103
|
||||||
|
return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]]
|
||||||
|
case i == 117:
|
||||||
|
return _Code_name_5
|
||||||
|
case 127 <= i && i <= 129:
|
||||||
|
i -= 127
|
||||||
|
return _Code_name_6[_Code_index_6[i]:_Code_index_6[i+1]]
|
||||||
|
case 224 <= i && i <= 231:
|
||||||
|
i -= 224
|
||||||
|
return _Code_name_7[_Code_index_7[i]:_Code_index_7[i+1]]
|
||||||
|
case i == 65536:
|
||||||
|
return _Code_name_8
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Code(%d)", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
+270
@@ -0,0 +1,270 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:generate stringer -type=Code
|
||||||
|
|
||||||
|
// Package key defines an event for physical keyboard keys.
|
||||||
|
//
|
||||||
|
// On-screen software keyboards do not send key events.
|
||||||
|
//
|
||||||
|
// See the github.com/ebitengine/gomobile/app package for details on the event model.
|
||||||
|
package key
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is a key event.
|
||||||
|
type Event struct {
|
||||||
|
// Rune is the meaning of the key event as determined by the
|
||||||
|
// operating system. The mapping is determined by system-dependent
|
||||||
|
// current layout, modifiers, lock-states, etc.
|
||||||
|
//
|
||||||
|
// If non-negative, it is a Unicode codepoint: pressing the 'a' key
|
||||||
|
// generates different Runes 'a' or 'A' (but the same Code) depending on
|
||||||
|
// the state of the shift key.
|
||||||
|
//
|
||||||
|
// If -1, the key does not generate a Unicode codepoint. To distinguish
|
||||||
|
// them, look at Code.
|
||||||
|
Rune rune
|
||||||
|
|
||||||
|
// Code is the identity of the physical key relative to a notional
|
||||||
|
// "standard" keyboard, independent of current layout, modifiers,
|
||||||
|
// lock-states, etc
|
||||||
|
//
|
||||||
|
// For standard key codes, its value matches USB HID key codes.
|
||||||
|
// Compare its value to uint32-typed constants in this package, such
|
||||||
|
// as CodeLeftShift and CodeEscape.
|
||||||
|
//
|
||||||
|
// Pressing the regular '2' key and number-pad '2' key (with Num-Lock)
|
||||||
|
// generate different Codes (but the same Rune).
|
||||||
|
Code Code
|
||||||
|
|
||||||
|
// Modifiers is a bitmask representing a set of modifier keys: ModShift,
|
||||||
|
// ModAlt, etc.
|
||||||
|
Modifiers Modifiers
|
||||||
|
|
||||||
|
// Direction is the direction of the key event: DirPress, DirRelease,
|
||||||
|
// or DirNone (for key repeats).
|
||||||
|
Direction Direction
|
||||||
|
|
||||||
|
// TODO: add a Device ID, for multiple input devices?
|
||||||
|
// TODO: add a time.Time?
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Event) String() string {
|
||||||
|
if e.Rune >= 0 {
|
||||||
|
return fmt.Sprintf("key.Event{%q (%v), %v, %v}", e.Rune, e.Code, e.Modifiers, e.Direction)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("key.Event{(%v), %v, %v}", e.Code, e.Modifiers, e.Direction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direction is the direction of the key event.
|
||||||
|
type Direction uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
DirNone Direction = 0
|
||||||
|
DirPress Direction = 1
|
||||||
|
DirRelease Direction = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Modifiers is a bitmask representing a set of modifier keys.
|
||||||
|
type Modifiers uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModShift Modifiers = 1 << 0
|
||||||
|
ModControl Modifiers = 1 << 1
|
||||||
|
ModAlt Modifiers = 1 << 2
|
||||||
|
ModMeta Modifiers = 1 << 3 // called "Command" on OS X
|
||||||
|
)
|
||||||
|
|
||||||
|
// Code is the identity of a key relative to a notional "standard" keyboard.
|
||||||
|
type Code uint32
|
||||||
|
|
||||||
|
// Physical key codes.
|
||||||
|
//
|
||||||
|
// For standard key codes, its value matches USB HID key codes.
|
||||||
|
// TODO: add missing codes.
|
||||||
|
const (
|
||||||
|
CodeUnknown Code = 0
|
||||||
|
|
||||||
|
CodeA Code = 4
|
||||||
|
CodeB Code = 5
|
||||||
|
CodeC Code = 6
|
||||||
|
CodeD Code = 7
|
||||||
|
CodeE Code = 8
|
||||||
|
CodeF Code = 9
|
||||||
|
CodeG Code = 10
|
||||||
|
CodeH Code = 11
|
||||||
|
CodeI Code = 12
|
||||||
|
CodeJ Code = 13
|
||||||
|
CodeK Code = 14
|
||||||
|
CodeL Code = 15
|
||||||
|
CodeM Code = 16
|
||||||
|
CodeN Code = 17
|
||||||
|
CodeO Code = 18
|
||||||
|
CodeP Code = 19
|
||||||
|
CodeQ Code = 20
|
||||||
|
CodeR Code = 21
|
||||||
|
CodeS Code = 22
|
||||||
|
CodeT Code = 23
|
||||||
|
CodeU Code = 24
|
||||||
|
CodeV Code = 25
|
||||||
|
CodeW Code = 26
|
||||||
|
CodeX Code = 27
|
||||||
|
CodeY Code = 28
|
||||||
|
CodeZ Code = 29
|
||||||
|
|
||||||
|
Code1 Code = 30
|
||||||
|
Code2 Code = 31
|
||||||
|
Code3 Code = 32
|
||||||
|
Code4 Code = 33
|
||||||
|
Code5 Code = 34
|
||||||
|
Code6 Code = 35
|
||||||
|
Code7 Code = 36
|
||||||
|
Code8 Code = 37
|
||||||
|
Code9 Code = 38
|
||||||
|
Code0 Code = 39
|
||||||
|
|
||||||
|
CodeReturnEnter Code = 40
|
||||||
|
CodeEscape Code = 41
|
||||||
|
CodeDeleteBackspace Code = 42
|
||||||
|
CodeTab Code = 43
|
||||||
|
CodeSpacebar Code = 44
|
||||||
|
CodeHyphenMinus Code = 45 // -
|
||||||
|
CodeEqualSign Code = 46 // =
|
||||||
|
CodeLeftSquareBracket Code = 47 // [
|
||||||
|
CodeRightSquareBracket Code = 48 // ]
|
||||||
|
CodeBackslash Code = 49 // \
|
||||||
|
CodeSemicolon Code = 51 // ;
|
||||||
|
CodeApostrophe Code = 52 // '
|
||||||
|
CodeGraveAccent Code = 53 // `
|
||||||
|
CodeComma Code = 54 // ,
|
||||||
|
CodeFullStop Code = 55 // .
|
||||||
|
CodeSlash Code = 56 // /
|
||||||
|
CodeCapsLock Code = 57
|
||||||
|
|
||||||
|
CodeF1 Code = 58
|
||||||
|
CodeF2 Code = 59
|
||||||
|
CodeF3 Code = 60
|
||||||
|
CodeF4 Code = 61
|
||||||
|
CodeF5 Code = 62
|
||||||
|
CodeF6 Code = 63
|
||||||
|
CodeF7 Code = 64
|
||||||
|
CodeF8 Code = 65
|
||||||
|
CodeF9 Code = 66
|
||||||
|
CodeF10 Code = 67
|
||||||
|
CodeF11 Code = 68
|
||||||
|
CodeF12 Code = 69
|
||||||
|
|
||||||
|
CodePause Code = 72
|
||||||
|
CodeInsert Code = 73
|
||||||
|
CodeHome Code = 74
|
||||||
|
CodePageUp Code = 75
|
||||||
|
CodeDeleteForward Code = 76
|
||||||
|
CodeEnd Code = 77
|
||||||
|
CodePageDown Code = 78
|
||||||
|
|
||||||
|
CodeRightArrow Code = 79
|
||||||
|
CodeLeftArrow Code = 80
|
||||||
|
CodeDownArrow Code = 81
|
||||||
|
CodeUpArrow Code = 82
|
||||||
|
|
||||||
|
CodeKeypadNumLock Code = 83
|
||||||
|
CodeKeypadSlash Code = 84 // /
|
||||||
|
CodeKeypadAsterisk Code = 85 // *
|
||||||
|
CodeKeypadHyphenMinus Code = 86 // -
|
||||||
|
CodeKeypadPlusSign Code = 87 // +
|
||||||
|
CodeKeypadEnter Code = 88
|
||||||
|
CodeKeypad1 Code = 89
|
||||||
|
CodeKeypad2 Code = 90
|
||||||
|
CodeKeypad3 Code = 91
|
||||||
|
CodeKeypad4 Code = 92
|
||||||
|
CodeKeypad5 Code = 93
|
||||||
|
CodeKeypad6 Code = 94
|
||||||
|
CodeKeypad7 Code = 95
|
||||||
|
CodeKeypad8 Code = 96
|
||||||
|
CodeKeypad9 Code = 97
|
||||||
|
CodeKeypad0 Code = 98
|
||||||
|
CodeKeypadFullStop Code = 99 // .
|
||||||
|
CodeKeypadEqualSign Code = 103 // =
|
||||||
|
|
||||||
|
CodeF13 Code = 104
|
||||||
|
CodeF14 Code = 105
|
||||||
|
CodeF15 Code = 106
|
||||||
|
CodeF16 Code = 107
|
||||||
|
CodeF17 Code = 108
|
||||||
|
CodeF18 Code = 109
|
||||||
|
CodeF19 Code = 110
|
||||||
|
CodeF20 Code = 111
|
||||||
|
CodeF21 Code = 112
|
||||||
|
CodeF22 Code = 113
|
||||||
|
CodeF23 Code = 114
|
||||||
|
CodeF24 Code = 115
|
||||||
|
|
||||||
|
CodeHelp Code = 117
|
||||||
|
|
||||||
|
CodeMute Code = 127
|
||||||
|
CodeVolumeUp Code = 128
|
||||||
|
CodeVolumeDown Code = 129
|
||||||
|
|
||||||
|
CodeLeftControl Code = 224
|
||||||
|
CodeLeftShift Code = 225
|
||||||
|
CodeLeftAlt Code = 226
|
||||||
|
CodeLeftGUI Code = 227
|
||||||
|
CodeRightControl Code = 228
|
||||||
|
CodeRightShift Code = 229
|
||||||
|
CodeRightAlt Code = 230
|
||||||
|
CodeRightGUI Code = 231
|
||||||
|
|
||||||
|
// The following codes are not part of the standard USB HID Usage IDs for
|
||||||
|
// keyboards. See http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
|
||||||
|
//
|
||||||
|
// Usage IDs are uint16s, so these non-standard values start at 0x10000.
|
||||||
|
|
||||||
|
// CodeCompose is the Code for a compose key, sometimes called a multi key,
|
||||||
|
// used to input non-ASCII characters such as ñ being composed of n and ~.
|
||||||
|
//
|
||||||
|
// See https://en.wikipedia.org/wiki/Compose_key
|
||||||
|
CodeCompose Code = 0x10000
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Given we use runes outside the unicode space, should we provide a
|
||||||
|
// printing function? Related: it's a little unfortunate that printing a
|
||||||
|
// key.Event with %v gives not very readable output like:
|
||||||
|
// {100 7 key.Modifiers() Press}
|
||||||
|
|
||||||
|
var mods = [...]struct {
|
||||||
|
m Modifiers
|
||||||
|
s string
|
||||||
|
}{
|
||||||
|
{ModShift, "Shift"},
|
||||||
|
{ModControl, "Control"},
|
||||||
|
{ModAlt, "Alt"},
|
||||||
|
{ModMeta, "Meta"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Modifiers) String() string {
|
||||||
|
var match []string
|
||||||
|
for _, mod := range mods {
|
||||||
|
if mod.m&m != 0 {
|
||||||
|
match = append(match, mod.s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "key.Modifiers(" + strings.Join(match, "|") + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Direction) String() string {
|
||||||
|
switch d {
|
||||||
|
case DirNone:
|
||||||
|
return "None"
|
||||||
|
case DirPress:
|
||||||
|
return "Press"
|
||||||
|
case DirRelease:
|
||||||
|
return "Release"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("key.Direction(%d)", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
// 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 lifecycle defines an event for an app's lifecycle.
|
||||||
|
//
|
||||||
|
// The app lifecycle consists of moving back and forth between an ordered
|
||||||
|
// sequence of stages. For example, being at a stage greater than or equal to
|
||||||
|
// StageVisible means that the app is visible on the screen.
|
||||||
|
//
|
||||||
|
// A lifecycle event is a change from one stage to another, which crosses every
|
||||||
|
// intermediate stage. For example, changing from StageAlive to StageFocused
|
||||||
|
// implicitly crosses StageVisible.
|
||||||
|
//
|
||||||
|
// Crosses can be in a positive or negative direction. A positive crossing of
|
||||||
|
// StageFocused means that the app has gained the focus. A negative crossing
|
||||||
|
// means it has lost the focus.
|
||||||
|
//
|
||||||
|
// See the github.com/ebitengine/gomobile/app package for details on the event model.
|
||||||
|
package lifecycle // import "github.com/ebitengine/gomobile/event/lifecycle"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cross is whether a lifecycle stage was crossed.
|
||||||
|
type Cross uint32
|
||||||
|
|
||||||
|
func (c Cross) String() string {
|
||||||
|
switch c {
|
||||||
|
case CrossOn:
|
||||||
|
return "on"
|
||||||
|
case CrossOff:
|
||||||
|
return "off"
|
||||||
|
}
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
CrossNone Cross = 0
|
||||||
|
CrossOn Cross = 1
|
||||||
|
CrossOff Cross = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is a lifecycle change from an old stage to a new stage.
|
||||||
|
type Event struct {
|
||||||
|
From, To Stage
|
||||||
|
|
||||||
|
// DrawContext is the state used for painting, if any is valid.
|
||||||
|
//
|
||||||
|
// For OpenGL apps, a non-nil DrawContext is a gl.Context.
|
||||||
|
//
|
||||||
|
// TODO: make this an App method if we move away from an event channel?
|
||||||
|
DrawContext interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Event) String() string {
|
||||||
|
return fmt.Sprintf("lifecycle.Event{From:%v, To:%v, DrawContext:%v}", e.From, e.To, e.DrawContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crosses reports whether the transition from From to To crosses the stage s:
|
||||||
|
// - It returns CrossOn if it does, and the lifecycle change is positive.
|
||||||
|
// - It returns CrossOff if it does, and the lifecycle change is negative.
|
||||||
|
// - Otherwise, it returns CrossNone.
|
||||||
|
//
|
||||||
|
// See the documentation for Stage for more discussion of positive and negative
|
||||||
|
// crosses.
|
||||||
|
func (e Event) Crosses(s Stage) Cross {
|
||||||
|
switch {
|
||||||
|
case e.From < s && e.To >= s:
|
||||||
|
return CrossOn
|
||||||
|
case e.From >= s && e.To < s:
|
||||||
|
return CrossOff
|
||||||
|
}
|
||||||
|
return CrossNone
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stage is a stage in the app's lifecycle. The values are ordered, so that a
|
||||||
|
// lifecycle change from stage From to stage To implicitly crosses every stage
|
||||||
|
// in the range (min, max], exclusive on the low end and inclusive on the high
|
||||||
|
// end, where min is the minimum of From and To, and max is the maximum.
|
||||||
|
//
|
||||||
|
// The documentation for individual stages talk about positive and negative
|
||||||
|
// crosses. A positive lifecycle change is one where its From stage is less
|
||||||
|
// than its To stage. Similarly, a negative lifecycle change is one where From
|
||||||
|
// is greater than To. Thus, a positive lifecycle change crosses every stage in
|
||||||
|
// the range (From, To] in increasing order, and a negative lifecycle change
|
||||||
|
// crosses every stage in the range (To, From] in decreasing order.
|
||||||
|
type Stage uint32
|
||||||
|
|
||||||
|
// TODO: how does iOS map to these stages? What do cross-platform mobile
|
||||||
|
// abstractions do?
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StageDead is the zero stage. No lifecycle change crosses this stage,
|
||||||
|
// but:
|
||||||
|
// - A positive change from this stage is the very first lifecycle change.
|
||||||
|
// - A negative change to this stage is the very last lifecycle change.
|
||||||
|
StageDead Stage = iota
|
||||||
|
|
||||||
|
// StageAlive means that the app is alive.
|
||||||
|
// - A positive cross means that the app has been created.
|
||||||
|
// - A negative cross means that the app is being destroyed.
|
||||||
|
// Each cross, either from or to StageDead, will occur only once.
|
||||||
|
// On Android, these correspond to onCreate and onDestroy.
|
||||||
|
StageAlive
|
||||||
|
|
||||||
|
// StageVisible means that the app window is visible.
|
||||||
|
// - A positive cross means that the app window has become visible.
|
||||||
|
// - A negative cross means that the app window has become invisible.
|
||||||
|
// On Android, these correspond to onStart and onStop.
|
||||||
|
// On Desktop, an app window can become invisible if e.g. it is minimized,
|
||||||
|
// unmapped, or not on a visible workspace.
|
||||||
|
StageVisible
|
||||||
|
|
||||||
|
// StageFocused means that the app window has the focus.
|
||||||
|
// - A positive cross means that the app window has gained the focus.
|
||||||
|
// - A negative cross means that the app window has lost the focus.
|
||||||
|
// On Android, these correspond to onResume and onFreeze.
|
||||||
|
StageFocused
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Stage) String() string {
|
||||||
|
switch s {
|
||||||
|
case StageDead:
|
||||||
|
return "StageDead"
|
||||||
|
case StageAlive:
|
||||||
|
return "StageAlive"
|
||||||
|
case StageVisible:
|
||||||
|
return "StageVisible"
|
||||||
|
case StageFocused:
|
||||||
|
return "StageFocused"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("lifecycle.Stage(%d)", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 paint defines an event for the app being ready to paint.
|
||||||
|
//
|
||||||
|
// See the github.com/ebitengine/gomobile/app package for details on the event model.
|
||||||
|
package paint // import "github.com/ebitengine/gomobile/event/paint"
|
||||||
|
|
||||||
|
// Event indicates that the app is ready to paint the next frame of the GUI.
|
||||||
|
//
|
||||||
|
// A frame is completed by calling the App's Publish method.
|
||||||
|
type Event struct {
|
||||||
|
// External is true for paint events sent by the screen driver.
|
||||||
|
//
|
||||||
|
// An external event may be sent at any time in response to an
|
||||||
|
// operating system event, for example the window opened, was
|
||||||
|
// resized, or the screen memory was lost.
|
||||||
|
//
|
||||||
|
// Programs actively drawing to the screen as fast as vsync allows
|
||||||
|
// should ignore external paint events to avoid a backlog of paint
|
||||||
|
// events building up.
|
||||||
|
External bool
|
||||||
|
}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
// 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 size defines an event for the dimensions, physical resolution and
|
||||||
|
// orientation of the app's window.
|
||||||
|
//
|
||||||
|
// See the github.com/ebitengine/gomobile/app package for details on the event model.
|
||||||
|
package size // import "github.com/ebitengine/gomobile/event/size"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
|
||||||
|
"github.com/ebitengine/gomobile/geom"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event holds the dimensions, physical resolution and orientation of the app's
|
||||||
|
// window.
|
||||||
|
type Event struct {
|
||||||
|
// WidthPx and HeightPx are the window's dimensions in pixels.
|
||||||
|
WidthPx, HeightPx int
|
||||||
|
|
||||||
|
// WidthPt and HeightPt are the window's physical dimensions in points
|
||||||
|
// (1/72 of an inch).
|
||||||
|
//
|
||||||
|
// The values are based on PixelsPerPt and are therefore approximate, as
|
||||||
|
// per the comment on PixelsPerPt.
|
||||||
|
WidthPt, HeightPt geom.Pt
|
||||||
|
|
||||||
|
// PixelsPerPt is the window's physical resolution. It is the number of
|
||||||
|
// pixels in a single geom.Pt, from the github.com/ebitengine/gomobile/geom package.
|
||||||
|
//
|
||||||
|
// There are a wide variety of pixel densities in existing phones and
|
||||||
|
// tablets, so apps should be written to expect various non-integer
|
||||||
|
// PixelsPerPt values. In general, work in geom.Pt.
|
||||||
|
//
|
||||||
|
// The value is approximate, in that the OS, drivers or hardware may report
|
||||||
|
// approximate or quantized values. An N x N pixel square should be roughly
|
||||||
|
// 1 square inch for N = int(PixelsPerPt * 72), although different square
|
||||||
|
// lengths (in pixels) might be closer to 1 inch in practice. Nonetheless,
|
||||||
|
// this PixelsPerPt value should be consistent with e.g. the ratio of
|
||||||
|
// WidthPx to WidthPt.
|
||||||
|
PixelsPerPt float32
|
||||||
|
|
||||||
|
// Orientation is the orientation of the device screen.
|
||||||
|
Orientation Orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the window's size in pixels, at the time this size event was
|
||||||
|
// sent.
|
||||||
|
func (e Event) Size() image.Point {
|
||||||
|
return image.Point{e.WidthPx, e.HeightPx}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounds returns the window's bounds in pixels, at the time this size event
|
||||||
|
// was sent.
|
||||||
|
//
|
||||||
|
// The top-left pixel is always (0, 0). The bottom-right pixel is given by the
|
||||||
|
// width and height.
|
||||||
|
func (e Event) Bounds() image.Rectangle {
|
||||||
|
return image.Rectangle{Max: image.Point{e.WidthPx, e.HeightPx}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orientation is the orientation of the device screen.
|
||||||
|
type Orientation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// OrientationUnknown means device orientation cannot be determined.
|
||||||
|
//
|
||||||
|
// Equivalent on Android to Configuration.ORIENTATION_UNKNOWN
|
||||||
|
// and on iOS to:
|
||||||
|
// UIDeviceOrientationUnknown
|
||||||
|
// UIDeviceOrientationFaceUp
|
||||||
|
// UIDeviceOrientationFaceDown
|
||||||
|
OrientationUnknown Orientation = iota
|
||||||
|
|
||||||
|
// OrientationPortrait is a device oriented so it is tall and thin.
|
||||||
|
//
|
||||||
|
// Equivalent on Android to Configuration.ORIENTATION_PORTRAIT
|
||||||
|
// and on iOS to:
|
||||||
|
// UIDeviceOrientationPortrait
|
||||||
|
// UIDeviceOrientationPortraitUpsideDown
|
||||||
|
OrientationPortrait
|
||||||
|
|
||||||
|
// OrientationLandscape is a device oriented so it is short and wide.
|
||||||
|
//
|
||||||
|
// Equivalent on Android to Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
// and on iOS to:
|
||||||
|
// UIDeviceOrientationLandscapeLeft
|
||||||
|
// UIDeviceOrientationLandscapeRight
|
||||||
|
OrientationLandscape
|
||||||
|
)
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
// 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 touch defines an event for touch input.
|
||||||
|
//
|
||||||
|
// See the github.com/ebitengine/gomobile/app package for details on the event model.
|
||||||
|
package touch // import "github.com/ebitengine/gomobile/event/touch"
|
||||||
|
|
||||||
|
// The best source on android input events is the NDK: include/android/input.h
|
||||||
|
//
|
||||||
|
// iOS event handling guide:
|
||||||
|
// https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event is a touch event.
|
||||||
|
type Event struct {
|
||||||
|
// X and Y are the touch location, in pixels.
|
||||||
|
X, Y float32
|
||||||
|
|
||||||
|
// Sequence is the sequence number. The same number is shared by all events
|
||||||
|
// in a sequence. A sequence begins with a single TypeBegin, is followed by
|
||||||
|
// zero or more TypeMoves, and ends with a single TypeEnd. A Sequence
|
||||||
|
// distinguishes concurrent sequences but its value is subsequently reused.
|
||||||
|
Sequence Sequence
|
||||||
|
|
||||||
|
// Type is the touch type.
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sequence identifies a sequence of touch events.
|
||||||
|
type Sequence int64
|
||||||
|
|
||||||
|
// Type describes the type of a touch event.
|
||||||
|
type Type byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TypeBegin is a user first touching the device.
|
||||||
|
//
|
||||||
|
// On Android, this is a AMOTION_EVENT_ACTION_DOWN.
|
||||||
|
// On iOS, this is a call to touchesBegan.
|
||||||
|
TypeBegin Type = iota
|
||||||
|
|
||||||
|
// TypeMove is a user dragging across the device.
|
||||||
|
//
|
||||||
|
// A TypeMove is delivered between a TypeBegin and TypeEnd.
|
||||||
|
//
|
||||||
|
// On Android, this is a AMOTION_EVENT_ACTION_MOVE.
|
||||||
|
// On iOS, this is a call to touchesMoved.
|
||||||
|
TypeMove
|
||||||
|
|
||||||
|
// TypeEnd is a user no longer touching the device.
|
||||||
|
//
|
||||||
|
// On Android, this is a AMOTION_EVENT_ACTION_UP.
|
||||||
|
// On iOS, this is a call to touchesEnded.
|
||||||
|
TypeEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Type) String() string {
|
||||||
|
switch t {
|
||||||
|
case TypeBegin:
|
||||||
|
return "begin"
|
||||||
|
case TypeMove:
|
||||||
|
return "move"
|
||||||
|
case TypeEnd:
|
||||||
|
return "end"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("touch.Type(%d)", t)
|
||||||
|
}
|
||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package geom defines a two-dimensional coordinate system.
|
||||||
|
|
||||||
|
The coordinate system is based on an left-handed Cartesian plane.
|
||||||
|
That is, X increases to the right and Y increases down. For (x,y),
|
||||||
|
|
||||||
|
(0,0) → (1,0)
|
||||||
|
↓ ↘
|
||||||
|
(0,1) (1,1)
|
||||||
|
|
||||||
|
The display window places the origin (0, 0) in the upper-left corner of
|
||||||
|
the screen. Positions on the plane are measured in typographic points,
|
||||||
|
1/72 of an inch, which is represented by the Pt type.
|
||||||
|
|
||||||
|
Any interface that draws to the screen using types from the geom package
|
||||||
|
scales the number of pixels to maintain a Pt as 1/72 of an inch.
|
||||||
|
*/
|
||||||
|
package geom // import "github.com/ebitengine/gomobile/geom"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Notes on the various underlying coordinate systems.
|
||||||
|
|
||||||
|
Both Android and iOS (UIKit) use upper-left-origin coordinate systems
|
||||||
|
with for events, however they have different units.
|
||||||
|
|
||||||
|
UIKit measures distance in points. A point is a single-pixel on a
|
||||||
|
pre-Retina display. UIKit maintains a scale factor that to turn points
|
||||||
|
into pixels. On current retina devices, the scale factor is 2.0.
|
||||||
|
|
||||||
|
A UIKit point does not correspond to a fixed physical distance, as the
|
||||||
|
iPhone has a 163 DPI/PPI (326 PPI retina) display, and the iPad has a
|
||||||
|
132 PPI (264 retina) display. Points are 32-bit floats.
|
||||||
|
|
||||||
|
Even though point is the official UIKit term, they are commonly called
|
||||||
|
pixels. Indeed, the units were equivalent until the retina display was
|
||||||
|
introduced.
|
||||||
|
|
||||||
|
N.b. as a UIKit point is unrelated to a typographic point, it is not
|
||||||
|
related to this packages's Pt and Point types.
|
||||||
|
|
||||||
|
More details about iOS drawing:
|
||||||
|
|
||||||
|
https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/GraphicsDrawingOverview/GraphicsDrawingOverview.html
|
||||||
|
|
||||||
|
Android uses pixels. Sub-pixel precision is possible, so pixels are
|
||||||
|
represented as 32-bit floats. The ACONFIGURATION_DENSITY enum provides
|
||||||
|
the screen DPI/PPI, which varies frequently between devices.
|
||||||
|
|
||||||
|
It would be tempting to adopt the pixel, given the clear pixel/DPI split
|
||||||
|
in the core android events API. However, the plot thickens:
|
||||||
|
|
||||||
|
http://developer.android.com/training/multiscreen/screendensities.html
|
||||||
|
|
||||||
|
Android promotes the notion of a density-independent pixel in many of
|
||||||
|
their interfaces, often prefixed by "dp". 1dp is a real physical length,
|
||||||
|
as "independent" means it is assumed to be 1/160th of an inch and is
|
||||||
|
adjusted for the current screen.
|
||||||
|
|
||||||
|
In addition, android has a scale-indepdendent pixel used for expressing
|
||||||
|
a user's preferred text size. The user text size preference is a useful
|
||||||
|
notion not yet expressed in the geom package.
|
||||||
|
|
||||||
|
For the sake of clarity when working across platforms, the geom package
|
||||||
|
tries to put distance between it and the word pixel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Pt is a length.
|
||||||
|
//
|
||||||
|
// The unit Pt is a typographical point, 1/72 of an inch (0.3527 mm).
|
||||||
|
//
|
||||||
|
// It can be converted to a length in current device pixels by
|
||||||
|
// multiplying with PixelsPerPt after app initialization is complete.
|
||||||
|
type Pt float32
|
||||||
|
|
||||||
|
// Px converts the length to current device pixels.
|
||||||
|
func (p Pt) Px(pixelsPerPt float32) float32 { return float32(p) * pixelsPerPt }
|
||||||
|
|
||||||
|
// String returns a string representation of p like "3.2pt".
|
||||||
|
func (p Pt) String() string { return fmt.Sprintf("%.2fpt", p) }
|
||||||
|
|
||||||
|
// Point is a point in a two-dimensional plane.
|
||||||
|
type Point struct {
|
||||||
|
X, Y Pt
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of p like "(1.2,3.4)".
|
||||||
|
func (p Point) String() string { return fmt.Sprintf("(%.2f,%.2f)", p.X, p.Y) }
|
||||||
|
|
||||||
|
// A Rectangle is region of points.
|
||||||
|
// The top-left point is Min, and the bottom-right point is Max.
|
||||||
|
type Rectangle struct {
|
||||||
|
Min, Max Point
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of r like "(3,4)-(6,5)".
|
||||||
|
func (r Rectangle) String() string { return r.Min.String() + "-" + r.Max.String() }
|
||||||
+657
@@ -0,0 +1,657 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
/*
|
||||||
|
Partially generated from the Khronos OpenGL API specification in XML
|
||||||
|
format, which is covered by the license:
|
||||||
|
|
||||||
|
Copyright (c) 2013-2014 The Khronos Group Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and/or associated documentation files (the
|
||||||
|
"Materials"), to deal in the Materials without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Materials.
|
||||||
|
|
||||||
|
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
POINTS = 0x0000
|
||||||
|
LINES = 0x0001
|
||||||
|
LINE_LOOP = 0x0002
|
||||||
|
LINE_STRIP = 0x0003
|
||||||
|
TRIANGLES = 0x0004
|
||||||
|
TRIANGLE_STRIP = 0x0005
|
||||||
|
TRIANGLE_FAN = 0x0006
|
||||||
|
SRC_COLOR = 0x0300
|
||||||
|
ONE_MINUS_SRC_COLOR = 0x0301
|
||||||
|
SRC_ALPHA = 0x0302
|
||||||
|
ONE_MINUS_SRC_ALPHA = 0x0303
|
||||||
|
DST_ALPHA = 0x0304
|
||||||
|
ONE_MINUS_DST_ALPHA = 0x0305
|
||||||
|
DST_COLOR = 0x0306
|
||||||
|
ONE_MINUS_DST_COLOR = 0x0307
|
||||||
|
SRC_ALPHA_SATURATE = 0x0308
|
||||||
|
FUNC_ADD = 0x8006
|
||||||
|
BLEND_EQUATION = 0x8009
|
||||||
|
BLEND_EQUATION_RGB = 0x8009
|
||||||
|
BLEND_EQUATION_ALPHA = 0x883D
|
||||||
|
FUNC_SUBTRACT = 0x800A
|
||||||
|
FUNC_REVERSE_SUBTRACT = 0x800B
|
||||||
|
BLEND_DST_RGB = 0x80C8
|
||||||
|
BLEND_SRC_RGB = 0x80C9
|
||||||
|
BLEND_DST_ALPHA = 0x80CA
|
||||||
|
BLEND_SRC_ALPHA = 0x80CB
|
||||||
|
CONSTANT_COLOR = 0x8001
|
||||||
|
ONE_MINUS_CONSTANT_COLOR = 0x8002
|
||||||
|
CONSTANT_ALPHA = 0x8003
|
||||||
|
ONE_MINUS_CONSTANT_ALPHA = 0x8004
|
||||||
|
BLEND_COLOR = 0x8005
|
||||||
|
ARRAY_BUFFER = 0x8892
|
||||||
|
ELEMENT_ARRAY_BUFFER = 0x8893
|
||||||
|
ARRAY_BUFFER_BINDING = 0x8894
|
||||||
|
ELEMENT_ARRAY_BUFFER_BINDING = 0x8895
|
||||||
|
STREAM_DRAW = 0x88E0
|
||||||
|
STATIC_DRAW = 0x88E4
|
||||||
|
DYNAMIC_DRAW = 0x88E8
|
||||||
|
BUFFER_SIZE = 0x8764
|
||||||
|
BUFFER_USAGE = 0x8765
|
||||||
|
CURRENT_VERTEX_ATTRIB = 0x8626
|
||||||
|
FRONT = 0x0404
|
||||||
|
BACK = 0x0405
|
||||||
|
FRONT_AND_BACK = 0x0408
|
||||||
|
TEXTURE_2D = 0x0DE1
|
||||||
|
CULL_FACE = 0x0B44
|
||||||
|
BLEND = 0x0BE2
|
||||||
|
DITHER = 0x0BD0
|
||||||
|
STENCIL_TEST = 0x0B90
|
||||||
|
DEPTH_TEST = 0x0B71
|
||||||
|
SCISSOR_TEST = 0x0C11
|
||||||
|
POLYGON_OFFSET_FILL = 0x8037
|
||||||
|
SAMPLE_ALPHA_TO_COVERAGE = 0x809E
|
||||||
|
SAMPLE_COVERAGE = 0x80A0
|
||||||
|
INVALID_ENUM = 0x0500
|
||||||
|
INVALID_VALUE = 0x0501
|
||||||
|
INVALID_OPERATION = 0x0502
|
||||||
|
OUT_OF_MEMORY = 0x0505
|
||||||
|
CW = 0x0900
|
||||||
|
CCW = 0x0901
|
||||||
|
LINE_WIDTH = 0x0B21
|
||||||
|
ALIASED_POINT_SIZE_RANGE = 0x846D
|
||||||
|
ALIASED_LINE_WIDTH_RANGE = 0x846E
|
||||||
|
CULL_FACE_MODE = 0x0B45
|
||||||
|
FRONT_FACE = 0x0B46
|
||||||
|
DEPTH_RANGE = 0x0B70
|
||||||
|
DEPTH_WRITEMASK = 0x0B72
|
||||||
|
DEPTH_CLEAR_VALUE = 0x0B73
|
||||||
|
DEPTH_FUNC = 0x0B74
|
||||||
|
STENCIL_CLEAR_VALUE = 0x0B91
|
||||||
|
STENCIL_FUNC = 0x0B92
|
||||||
|
STENCIL_FAIL = 0x0B94
|
||||||
|
STENCIL_PASS_DEPTH_FAIL = 0x0B95
|
||||||
|
STENCIL_PASS_DEPTH_PASS = 0x0B96
|
||||||
|
STENCIL_REF = 0x0B97
|
||||||
|
STENCIL_VALUE_MASK = 0x0B93
|
||||||
|
STENCIL_WRITEMASK = 0x0B98
|
||||||
|
STENCIL_BACK_FUNC = 0x8800
|
||||||
|
STENCIL_BACK_FAIL = 0x8801
|
||||||
|
STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802
|
||||||
|
STENCIL_BACK_PASS_DEPTH_PASS = 0x8803
|
||||||
|
STENCIL_BACK_REF = 0x8CA3
|
||||||
|
STENCIL_BACK_VALUE_MASK = 0x8CA4
|
||||||
|
STENCIL_BACK_WRITEMASK = 0x8CA5
|
||||||
|
VIEWPORT = 0x0BA2
|
||||||
|
SCISSOR_BOX = 0x0C10
|
||||||
|
COLOR_CLEAR_VALUE = 0x0C22
|
||||||
|
COLOR_WRITEMASK = 0x0C23
|
||||||
|
UNPACK_ALIGNMENT = 0x0CF5
|
||||||
|
PACK_ALIGNMENT = 0x0D05
|
||||||
|
MAX_TEXTURE_SIZE = 0x0D33
|
||||||
|
MAX_VIEWPORT_DIMS = 0x0D3A
|
||||||
|
SUBPIXEL_BITS = 0x0D50
|
||||||
|
RED_BITS = 0x0D52
|
||||||
|
GREEN_BITS = 0x0D53
|
||||||
|
BLUE_BITS = 0x0D54
|
||||||
|
ALPHA_BITS = 0x0D55
|
||||||
|
DEPTH_BITS = 0x0D56
|
||||||
|
STENCIL_BITS = 0x0D57
|
||||||
|
POLYGON_OFFSET_UNITS = 0x2A00
|
||||||
|
POLYGON_OFFSET_FACTOR = 0x8038
|
||||||
|
TEXTURE_BINDING_2D = 0x8069
|
||||||
|
SAMPLE_BUFFERS = 0x80A8
|
||||||
|
SAMPLES = 0x80A9
|
||||||
|
SAMPLE_COVERAGE_VALUE = 0x80AA
|
||||||
|
SAMPLE_COVERAGE_INVERT = 0x80AB
|
||||||
|
NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2
|
||||||
|
COMPRESSED_TEXTURE_FORMATS = 0x86A3
|
||||||
|
DONT_CARE = 0x1100
|
||||||
|
FASTEST = 0x1101
|
||||||
|
NICEST = 0x1102
|
||||||
|
GENERATE_MIPMAP_HINT = 0x8192
|
||||||
|
BYTE = 0x1400
|
||||||
|
UNSIGNED_BYTE = 0x1401
|
||||||
|
SHORT = 0x1402
|
||||||
|
UNSIGNED_SHORT = 0x1403
|
||||||
|
INT = 0x1404
|
||||||
|
UNSIGNED_INT = 0x1405
|
||||||
|
FLOAT = 0x1406
|
||||||
|
FIXED = 0x140C
|
||||||
|
DEPTH_COMPONENT = 0x1902
|
||||||
|
ALPHA = 0x1906
|
||||||
|
RGB = 0x1907
|
||||||
|
RGBA = 0x1908
|
||||||
|
LUMINANCE = 0x1909
|
||||||
|
LUMINANCE_ALPHA = 0x190A
|
||||||
|
UNSIGNED_SHORT_4_4_4_4 = 0x8033
|
||||||
|
UNSIGNED_SHORT_5_5_5_1 = 0x8034
|
||||||
|
UNSIGNED_SHORT_5_6_5 = 0x8363
|
||||||
|
MAX_VERTEX_ATTRIBS = 0x8869
|
||||||
|
MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB
|
||||||
|
MAX_VARYING_VECTORS = 0x8DFC
|
||||||
|
MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D
|
||||||
|
MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C
|
||||||
|
MAX_TEXTURE_IMAGE_UNITS = 0x8872
|
||||||
|
MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD
|
||||||
|
SHADER_TYPE = 0x8B4F
|
||||||
|
DELETE_STATUS = 0x8B80
|
||||||
|
LINK_STATUS = 0x8B82
|
||||||
|
VALIDATE_STATUS = 0x8B83
|
||||||
|
ATTACHED_SHADERS = 0x8B85
|
||||||
|
ACTIVE_UNIFORMS = 0x8B86
|
||||||
|
ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87
|
||||||
|
ACTIVE_ATTRIBUTES = 0x8B89
|
||||||
|
ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A
|
||||||
|
SHADING_LANGUAGE_VERSION = 0x8B8C
|
||||||
|
CURRENT_PROGRAM = 0x8B8D
|
||||||
|
NEVER = 0x0200
|
||||||
|
LESS = 0x0201
|
||||||
|
EQUAL = 0x0202
|
||||||
|
LEQUAL = 0x0203
|
||||||
|
GREATER = 0x0204
|
||||||
|
NOTEQUAL = 0x0205
|
||||||
|
GEQUAL = 0x0206
|
||||||
|
ALWAYS = 0x0207
|
||||||
|
KEEP = 0x1E00
|
||||||
|
REPLACE = 0x1E01
|
||||||
|
INCR = 0x1E02
|
||||||
|
DECR = 0x1E03
|
||||||
|
INVERT = 0x150A
|
||||||
|
INCR_WRAP = 0x8507
|
||||||
|
DECR_WRAP = 0x8508
|
||||||
|
VENDOR = 0x1F00
|
||||||
|
RENDERER = 0x1F01
|
||||||
|
VERSION = 0x1F02
|
||||||
|
EXTENSIONS = 0x1F03
|
||||||
|
NEAREST = 0x2600
|
||||||
|
LINEAR = 0x2601
|
||||||
|
NEAREST_MIPMAP_NEAREST = 0x2700
|
||||||
|
LINEAR_MIPMAP_NEAREST = 0x2701
|
||||||
|
NEAREST_MIPMAP_LINEAR = 0x2702
|
||||||
|
LINEAR_MIPMAP_LINEAR = 0x2703
|
||||||
|
TEXTURE_MAG_FILTER = 0x2800
|
||||||
|
TEXTURE_MIN_FILTER = 0x2801
|
||||||
|
TEXTURE_WRAP_S = 0x2802
|
||||||
|
TEXTURE_WRAP_T = 0x2803
|
||||||
|
TEXTURE = 0x1702
|
||||||
|
TEXTURE_CUBE_MAP = 0x8513
|
||||||
|
TEXTURE_BINDING_CUBE_MAP = 0x8514
|
||||||
|
TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515
|
||||||
|
TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516
|
||||||
|
TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517
|
||||||
|
TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518
|
||||||
|
TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519
|
||||||
|
TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A
|
||||||
|
MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C
|
||||||
|
TEXTURE0 = 0x84C0
|
||||||
|
TEXTURE1 = 0x84C1
|
||||||
|
TEXTURE2 = 0x84C2
|
||||||
|
TEXTURE3 = 0x84C3
|
||||||
|
TEXTURE4 = 0x84C4
|
||||||
|
TEXTURE5 = 0x84C5
|
||||||
|
TEXTURE6 = 0x84C6
|
||||||
|
TEXTURE7 = 0x84C7
|
||||||
|
TEXTURE8 = 0x84C8
|
||||||
|
TEXTURE9 = 0x84C9
|
||||||
|
TEXTURE10 = 0x84CA
|
||||||
|
TEXTURE11 = 0x84CB
|
||||||
|
TEXTURE12 = 0x84CC
|
||||||
|
TEXTURE13 = 0x84CD
|
||||||
|
TEXTURE14 = 0x84CE
|
||||||
|
TEXTURE15 = 0x84CF
|
||||||
|
TEXTURE16 = 0x84D0
|
||||||
|
TEXTURE17 = 0x84D1
|
||||||
|
TEXTURE18 = 0x84D2
|
||||||
|
TEXTURE19 = 0x84D3
|
||||||
|
TEXTURE20 = 0x84D4
|
||||||
|
TEXTURE21 = 0x84D5
|
||||||
|
TEXTURE22 = 0x84D6
|
||||||
|
TEXTURE23 = 0x84D7
|
||||||
|
TEXTURE24 = 0x84D8
|
||||||
|
TEXTURE25 = 0x84D9
|
||||||
|
TEXTURE26 = 0x84DA
|
||||||
|
TEXTURE27 = 0x84DB
|
||||||
|
TEXTURE28 = 0x84DC
|
||||||
|
TEXTURE29 = 0x84DD
|
||||||
|
TEXTURE30 = 0x84DE
|
||||||
|
TEXTURE31 = 0x84DF
|
||||||
|
ACTIVE_TEXTURE = 0x84E0
|
||||||
|
REPEAT = 0x2901
|
||||||
|
CLAMP_TO_EDGE = 0x812F
|
||||||
|
MIRRORED_REPEAT = 0x8370
|
||||||
|
VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622
|
||||||
|
VERTEX_ATTRIB_ARRAY_SIZE = 0x8623
|
||||||
|
VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624
|
||||||
|
VERTEX_ATTRIB_ARRAY_TYPE = 0x8625
|
||||||
|
VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A
|
||||||
|
VERTEX_ATTRIB_ARRAY_POINTER = 0x8645
|
||||||
|
VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F
|
||||||
|
IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A
|
||||||
|
IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B
|
||||||
|
COMPILE_STATUS = 0x8B81
|
||||||
|
INFO_LOG_LENGTH = 0x8B84
|
||||||
|
SHADER_SOURCE_LENGTH = 0x8B88
|
||||||
|
SHADER_COMPILER = 0x8DFA
|
||||||
|
SHADER_BINARY_FORMATS = 0x8DF8
|
||||||
|
NUM_SHADER_BINARY_FORMATS = 0x8DF9
|
||||||
|
LOW_FLOAT = 0x8DF0
|
||||||
|
MEDIUM_FLOAT = 0x8DF1
|
||||||
|
HIGH_FLOAT = 0x8DF2
|
||||||
|
LOW_INT = 0x8DF3
|
||||||
|
MEDIUM_INT = 0x8DF4
|
||||||
|
HIGH_INT = 0x8DF5
|
||||||
|
FRAMEBUFFER = 0x8D40
|
||||||
|
RENDERBUFFER = 0x8D41
|
||||||
|
RGBA4 = 0x8056
|
||||||
|
RGB5_A1 = 0x8057
|
||||||
|
RGB565 = 0x8D62
|
||||||
|
DEPTH_COMPONENT16 = 0x81A5
|
||||||
|
STENCIL_INDEX8 = 0x8D48
|
||||||
|
RENDERBUFFER_WIDTH = 0x8D42
|
||||||
|
RENDERBUFFER_HEIGHT = 0x8D43
|
||||||
|
RENDERBUFFER_INTERNAL_FORMAT = 0x8D44
|
||||||
|
RENDERBUFFER_RED_SIZE = 0x8D50
|
||||||
|
RENDERBUFFER_GREEN_SIZE = 0x8D51
|
||||||
|
RENDERBUFFER_BLUE_SIZE = 0x8D52
|
||||||
|
RENDERBUFFER_ALPHA_SIZE = 0x8D53
|
||||||
|
RENDERBUFFER_DEPTH_SIZE = 0x8D54
|
||||||
|
RENDERBUFFER_STENCIL_SIZE = 0x8D55
|
||||||
|
FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0
|
||||||
|
FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1
|
||||||
|
FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2
|
||||||
|
FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3
|
||||||
|
COLOR_ATTACHMENT0 = 0x8CE0
|
||||||
|
DEPTH_ATTACHMENT = 0x8D00
|
||||||
|
STENCIL_ATTACHMENT = 0x8D20
|
||||||
|
FRAMEBUFFER_COMPLETE = 0x8CD5
|
||||||
|
FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6
|
||||||
|
FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7
|
||||||
|
FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9
|
||||||
|
FRAMEBUFFER_UNSUPPORTED = 0x8CDD
|
||||||
|
FRAMEBUFFER_BINDING = 0x8CA6
|
||||||
|
RENDERBUFFER_BINDING = 0x8CA7
|
||||||
|
MAX_RENDERBUFFER_SIZE = 0x84E8
|
||||||
|
INVALID_FRAMEBUFFER_OPERATION = 0x0506
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DEPTH_BUFFER_BIT = 0x00000100
|
||||||
|
STENCIL_BUFFER_BIT = 0x00000400
|
||||||
|
COLOR_BUFFER_BIT = 0x00004000
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FLOAT_VEC2 = 0x8B50
|
||||||
|
FLOAT_VEC3 = 0x8B51
|
||||||
|
FLOAT_VEC4 = 0x8B52
|
||||||
|
INT_VEC2 = 0x8B53
|
||||||
|
INT_VEC3 = 0x8B54
|
||||||
|
INT_VEC4 = 0x8B55
|
||||||
|
BOOL = 0x8B56
|
||||||
|
BOOL_VEC2 = 0x8B57
|
||||||
|
BOOL_VEC3 = 0x8B58
|
||||||
|
BOOL_VEC4 = 0x8B59
|
||||||
|
FLOAT_MAT2 = 0x8B5A
|
||||||
|
FLOAT_MAT3 = 0x8B5B
|
||||||
|
FLOAT_MAT4 = 0x8B5C
|
||||||
|
SAMPLER_2D = 0x8B5E
|
||||||
|
SAMPLER_CUBE = 0x8B60
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FRAGMENT_SHADER = 0x8B30
|
||||||
|
VERTEX_SHADER = 0x8B31
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FALSE = 0
|
||||||
|
TRUE = 1
|
||||||
|
ZERO = 0
|
||||||
|
ONE = 1
|
||||||
|
NO_ERROR = 0
|
||||||
|
NONE = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// GL ES 3.0 constants.
|
||||||
|
const (
|
||||||
|
ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 0x8A35
|
||||||
|
ACTIVE_UNIFORM_BLOCKS = 0x8A36
|
||||||
|
ALREADY_SIGNALED = 0x911A
|
||||||
|
ANY_SAMPLES_PASSED = 0x8C2F
|
||||||
|
ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A
|
||||||
|
BLUE = 0x1905
|
||||||
|
BUFFER_ACCESS_FLAGS = 0x911F
|
||||||
|
BUFFER_MAP_LENGTH = 0x9120
|
||||||
|
BUFFER_MAP_OFFSET = 0x9121
|
||||||
|
BUFFER_MAPPED = 0x88BC
|
||||||
|
BUFFER_MAP_POINTER = 0x88BD
|
||||||
|
COLOR = 0x1800
|
||||||
|
COLOR_ATTACHMENT10 = 0x8CEA
|
||||||
|
COLOR_ATTACHMENT1 = 0x8CE1
|
||||||
|
COLOR_ATTACHMENT11 = 0x8CEB
|
||||||
|
COLOR_ATTACHMENT12 = 0x8CEC
|
||||||
|
COLOR_ATTACHMENT13 = 0x8CED
|
||||||
|
COLOR_ATTACHMENT14 = 0x8CEE
|
||||||
|
COLOR_ATTACHMENT15 = 0x8CEF
|
||||||
|
COLOR_ATTACHMENT2 = 0x8CE2
|
||||||
|
COLOR_ATTACHMENT3 = 0x8CE3
|
||||||
|
COLOR_ATTACHMENT4 = 0x8CE4
|
||||||
|
COLOR_ATTACHMENT5 = 0x8CE5
|
||||||
|
COLOR_ATTACHMENT6 = 0x8CE6
|
||||||
|
COLOR_ATTACHMENT7 = 0x8CE7
|
||||||
|
COLOR_ATTACHMENT8 = 0x8CE8
|
||||||
|
COLOR_ATTACHMENT9 = 0x8CE9
|
||||||
|
COMPARE_REF_TO_TEXTURE = 0x884E
|
||||||
|
COMPRESSED_R11_EAC = 0x9270
|
||||||
|
COMPRESSED_RG11_EAC = 0x9272
|
||||||
|
COMPRESSED_RGB8_ETC2 = 0x9274
|
||||||
|
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276
|
||||||
|
COMPRESSED_RGBA8_ETC2_EAC = 0x9278
|
||||||
|
COMPRESSED_SIGNED_R11_EAC = 0x9271
|
||||||
|
COMPRESSED_SIGNED_RG11_EAC = 0x9273
|
||||||
|
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279
|
||||||
|
COMPRESSED_SRGB8_ETC2 = 0x9275
|
||||||
|
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277
|
||||||
|
CONDITION_SATISFIED = 0x911C
|
||||||
|
COPY_READ_BUFFER = 0x8F36
|
||||||
|
COPY_READ_BUFFER_BINDING = 0x8F36
|
||||||
|
COPY_WRITE_BUFFER = 0x8F37
|
||||||
|
COPY_WRITE_BUFFER_BINDING = 0x8F37
|
||||||
|
CURRENT_QUERY = 0x8865
|
||||||
|
DEPTH = 0x1801
|
||||||
|
DEPTH24_STENCIL8 = 0x88F0
|
||||||
|
DEPTH32F_STENCIL8 = 0x8CAD
|
||||||
|
DEPTH_COMPONENT24 = 0x81A6
|
||||||
|
DEPTH_COMPONENT32F = 0x8CAC
|
||||||
|
DEPTH_STENCIL = 0x84F9
|
||||||
|
DEPTH_STENCIL_ATTACHMENT = 0x821A
|
||||||
|
DRAW_BUFFER0 = 0x8825
|
||||||
|
DRAW_BUFFER10 = 0x882F
|
||||||
|
DRAW_BUFFER1 = 0x8826
|
||||||
|
DRAW_BUFFER11 = 0x8830
|
||||||
|
DRAW_BUFFER12 = 0x8831
|
||||||
|
DRAW_BUFFER13 = 0x8832
|
||||||
|
DRAW_BUFFER14 = 0x8833
|
||||||
|
DRAW_BUFFER15 = 0x8834
|
||||||
|
DRAW_BUFFER2 = 0x8827
|
||||||
|
DRAW_BUFFER3 = 0x8828
|
||||||
|
DRAW_BUFFER4 = 0x8829
|
||||||
|
DRAW_BUFFER5 = 0x882A
|
||||||
|
DRAW_BUFFER6 = 0x882B
|
||||||
|
DRAW_BUFFER7 = 0x882C
|
||||||
|
DRAW_BUFFER8 = 0x882D
|
||||||
|
DRAW_BUFFER9 = 0x882E
|
||||||
|
DRAW_FRAMEBUFFER = 0x8CA9
|
||||||
|
DRAW_FRAMEBUFFER_BINDING = 0x8CA6
|
||||||
|
DYNAMIC_COPY = 0x88EA
|
||||||
|
DYNAMIC_READ = 0x88E9
|
||||||
|
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD
|
||||||
|
FLOAT_MAT2x3 = 0x8B65
|
||||||
|
FLOAT_MAT2x4 = 0x8B66
|
||||||
|
FLOAT_MAT3x2 = 0x8B67
|
||||||
|
FLOAT_MAT3x4 = 0x8B68
|
||||||
|
FLOAT_MAT4x2 = 0x8B69
|
||||||
|
FLOAT_MAT4x3 = 0x8B6A
|
||||||
|
FRAGMENT_SHADER_DERIVATIVE_HINT = 0x8B8B
|
||||||
|
FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x8215
|
||||||
|
FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x8214
|
||||||
|
FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210
|
||||||
|
FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x8211
|
||||||
|
FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216
|
||||||
|
FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x8213
|
||||||
|
FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x8212
|
||||||
|
FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217
|
||||||
|
FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x8CD4
|
||||||
|
FRAMEBUFFER_DEFAULT = 0x8218
|
||||||
|
FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x8D56
|
||||||
|
FRAMEBUFFER_UNDEFINED = 0x8219
|
||||||
|
GREEN = 0x1904
|
||||||
|
HALF_FLOAT = 0x140B
|
||||||
|
INT_2_10_10_10_REV = 0x8D9F
|
||||||
|
INTERLEAVED_ATTRIBS = 0x8C8C
|
||||||
|
INT_SAMPLER_2D = 0x8DCA
|
||||||
|
INT_SAMPLER_2D_ARRAY = 0x8DCF
|
||||||
|
INT_SAMPLER_3D = 0x8DCB
|
||||||
|
INT_SAMPLER_CUBE = 0x8DCC
|
||||||
|
INVALID_INDEX = 0xFFFFFFFF
|
||||||
|
MAJOR_VERSION = 0x821B
|
||||||
|
MAP_FLUSH_EXPLICIT_BIT = 0x0010
|
||||||
|
MAP_INVALIDATE_BUFFER_BIT = 0x0008
|
||||||
|
MAP_INVALIDATE_RANGE_BIT = 0x0004
|
||||||
|
MAP_READ_BIT = 0x0001
|
||||||
|
MAP_UNSYNCHRONIZED_BIT = 0x0020
|
||||||
|
MAP_WRITE_BIT = 0x0002
|
||||||
|
MAX = 0x8008
|
||||||
|
MAX_3D_TEXTURE_SIZE = 0x8073
|
||||||
|
MAX_ARRAY_TEXTURE_LAYERS = 0x88FF
|
||||||
|
MAX_COLOR_ATTACHMENTS = 0x8CDF
|
||||||
|
MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x8A33
|
||||||
|
MAX_COMBINED_UNIFORM_BLOCKS = 0x8A2E
|
||||||
|
MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x8A31
|
||||||
|
MAX_DRAW_BUFFERS = 0x8824
|
||||||
|
MAX_ELEMENT_INDEX = 0x8D6B
|
||||||
|
MAX_ELEMENTS_INDICES = 0x80E9
|
||||||
|
MAX_ELEMENTS_VERTICES = 0x80E8
|
||||||
|
MAX_FRAGMENT_INPUT_COMPONENTS = 0x9125
|
||||||
|
MAX_FRAGMENT_UNIFORM_BLOCKS = 0x8A2D
|
||||||
|
MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x8B49
|
||||||
|
MAX_PROGRAM_TEXEL_OFFSET = 0x8905
|
||||||
|
MAX_SAMPLES = 0x8D57
|
||||||
|
MAX_SERVER_WAIT_TIMEOUT = 0x9111
|
||||||
|
MAX_TEXTURE_LOD_BIAS = 0x84FD
|
||||||
|
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A
|
||||||
|
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B
|
||||||
|
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x8C80
|
||||||
|
MAX_UNIFORM_BLOCK_SIZE = 0x8A30
|
||||||
|
MAX_UNIFORM_BUFFER_BINDINGS = 0x8A2F
|
||||||
|
MAX_VARYING_COMPONENTS = 0x8B4B
|
||||||
|
MAX_VERTEX_OUTPUT_COMPONENTS = 0x9122
|
||||||
|
MAX_VERTEX_UNIFORM_BLOCKS = 0x8A2B
|
||||||
|
MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A
|
||||||
|
MIN = 0x8007
|
||||||
|
MINOR_VERSION = 0x821C
|
||||||
|
MIN_PROGRAM_TEXEL_OFFSET = 0x8904
|
||||||
|
NUM_EXTENSIONS = 0x821D
|
||||||
|
NUM_PROGRAM_BINARY_FORMATS = 0x87FE
|
||||||
|
NUM_SAMPLE_COUNTS = 0x9380
|
||||||
|
OBJECT_TYPE = 0x9112
|
||||||
|
PACK_ROW_LENGTH = 0x0D02
|
||||||
|
PACK_SKIP_PIXELS = 0x0D04
|
||||||
|
PACK_SKIP_ROWS = 0x0D03
|
||||||
|
PIXEL_PACK_BUFFER = 0x88EB
|
||||||
|
PIXEL_PACK_BUFFER_BINDING = 0x88ED
|
||||||
|
PIXEL_UNPACK_BUFFER = 0x88EC
|
||||||
|
PIXEL_UNPACK_BUFFER_BINDING = 0x88EF
|
||||||
|
PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69
|
||||||
|
PROGRAM_BINARY_FORMATS = 0x87FF
|
||||||
|
PROGRAM_BINARY_LENGTH = 0x8741
|
||||||
|
PROGRAM_BINARY_RETRIEVABLE_HINT = 0x8257
|
||||||
|
QUERY_RESULT = 0x8866
|
||||||
|
QUERY_RESULT_AVAILABLE = 0x8867
|
||||||
|
R11F_G11F_B10F = 0x8C3A
|
||||||
|
R16F = 0x822D
|
||||||
|
R16I = 0x8233
|
||||||
|
R16UI = 0x8234
|
||||||
|
R32F = 0x822E
|
||||||
|
R32I = 0x8235
|
||||||
|
R32UI = 0x8236
|
||||||
|
R8 = 0x8229
|
||||||
|
R8I = 0x8231
|
||||||
|
R8_SNORM = 0x8F94
|
||||||
|
R8UI = 0x8232
|
||||||
|
RASTERIZER_DISCARD = 0x8C89
|
||||||
|
READ_BUFFER = 0x0C02
|
||||||
|
READ_FRAMEBUFFER = 0x8CA8
|
||||||
|
READ_FRAMEBUFFER_BINDING = 0x8CAA
|
||||||
|
RED = 0x1903
|
||||||
|
RED_INTEGER = 0x8D94
|
||||||
|
RENDERBUFFER_SAMPLES = 0x8CAB
|
||||||
|
RG = 0x8227
|
||||||
|
RG16F = 0x822F
|
||||||
|
RG16I = 0x8239
|
||||||
|
RG16UI = 0x823A
|
||||||
|
RG32F = 0x8230
|
||||||
|
RG32I = 0x823B
|
||||||
|
RG32UI = 0x823C
|
||||||
|
RG8 = 0x822B
|
||||||
|
RG8I = 0x8237
|
||||||
|
RG8_SNORM = 0x8F95
|
||||||
|
RG8UI = 0x8238
|
||||||
|
RGB10_A2 = 0x8059
|
||||||
|
RGB10_A2UI = 0x906F
|
||||||
|
RGB16F = 0x881B
|
||||||
|
RGB16I = 0x8D89
|
||||||
|
RGB16UI = 0x8D77
|
||||||
|
RGB32F = 0x8815
|
||||||
|
RGB32I = 0x8D83
|
||||||
|
RGB32UI = 0x8D71
|
||||||
|
RGB8 = 0x8051
|
||||||
|
RGB8I = 0x8D8F
|
||||||
|
RGB8_SNORM = 0x8F96
|
||||||
|
RGB8UI = 0x8D7D
|
||||||
|
RGB9_E5 = 0x8C3D
|
||||||
|
RGBA16F = 0x881A
|
||||||
|
RGBA16I = 0x8D88
|
||||||
|
RGBA16UI = 0x8D76
|
||||||
|
RGBA32F = 0x8814
|
||||||
|
RGBA32I = 0x8D82
|
||||||
|
RGBA32UI = 0x8D70
|
||||||
|
RGBA8 = 0x8058
|
||||||
|
RGBA8I = 0x8D8E
|
||||||
|
RGBA8_SNORM = 0x8F97
|
||||||
|
RGBA8UI = 0x8D7C
|
||||||
|
RGBA_INTEGER = 0x8D99
|
||||||
|
RGB_INTEGER = 0x8D98
|
||||||
|
RG_INTEGER = 0x8228
|
||||||
|
SAMPLER_2D_ARRAY = 0x8DC1
|
||||||
|
SAMPLER_2D_ARRAY_SHADOW = 0x8DC4
|
||||||
|
SAMPLER_2D_SHADOW = 0x8B62
|
||||||
|
SAMPLER_3D = 0x8B5F
|
||||||
|
SAMPLER_BINDING = 0x8919
|
||||||
|
SAMPLER_CUBE_SHADOW = 0x8DC5
|
||||||
|
SEPARATE_ATTRIBS = 0x8C8D
|
||||||
|
SIGNALED = 0x9119
|
||||||
|
SIGNED_NORMALIZED = 0x8F9C
|
||||||
|
SRGB = 0x8C40
|
||||||
|
SRGB8 = 0x8C41
|
||||||
|
SRGB8_ALPHA8 = 0x8C43
|
||||||
|
STATIC_COPY = 0x88E6
|
||||||
|
STATIC_READ = 0x88E5
|
||||||
|
STENCIL = 0x1802
|
||||||
|
STREAM_COPY = 0x88E2
|
||||||
|
STREAM_READ = 0x88E1
|
||||||
|
SYNC_CONDITION = 0x9113
|
||||||
|
SYNC_FENCE = 0x9116
|
||||||
|
SYNC_FLAGS = 0x9115
|
||||||
|
SYNC_FLUSH_COMMANDS_BIT = 0x00000001
|
||||||
|
SYNC_GPU_COMMANDS_COMPLETE = 0x9117
|
||||||
|
SYNC_STATUS = 0x9114
|
||||||
|
TEXTURE_2D_ARRAY = 0x8C1A
|
||||||
|
TEXTURE_3D = 0x806F
|
||||||
|
TEXTURE_BASE_LEVEL = 0x813C
|
||||||
|
TEXTURE_BINDING_2D_ARRAY = 0x8C1D
|
||||||
|
TEXTURE_BINDING_3D = 0x806A
|
||||||
|
TEXTURE_COMPARE_FUNC = 0x884D
|
||||||
|
TEXTURE_COMPARE_MODE = 0x884C
|
||||||
|
TEXTURE_IMMUTABLE_FORMAT = 0x912F
|
||||||
|
TEXTURE_IMMUTABLE_LEVELS = 0x82DF
|
||||||
|
TEXTURE_MAX_LEVEL = 0x813D
|
||||||
|
TEXTURE_MAX_LOD = 0x813B
|
||||||
|
TEXTURE_MIN_LOD = 0x813A
|
||||||
|
TEXTURE_SWIZZLE_A = 0x8E45
|
||||||
|
TEXTURE_SWIZZLE_B = 0x8E44
|
||||||
|
TEXTURE_SWIZZLE_G = 0x8E43
|
||||||
|
TEXTURE_SWIZZLE_R = 0x8E42
|
||||||
|
TEXTURE_WRAP_R = 0x8072
|
||||||
|
TIMEOUT_EXPIRED = 0x911B
|
||||||
|
TIMEOUT_IGNORED = 0xFFFFFFFFFFFFFFFF
|
||||||
|
TRANSFORM_FEEDBACK = 0x8E22
|
||||||
|
TRANSFORM_FEEDBACK_ACTIVE = 0x8E24
|
||||||
|
TRANSFORM_FEEDBACK_BINDING = 0x8E25
|
||||||
|
TRANSFORM_FEEDBACK_BUFFER = 0x8C8E
|
||||||
|
TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F
|
||||||
|
TRANSFORM_FEEDBACK_BUFFER_MODE = 0x8C7F
|
||||||
|
TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85
|
||||||
|
TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84
|
||||||
|
TRANSFORM_FEEDBACK_PAUSED = 0x8E23
|
||||||
|
TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x8C88
|
||||||
|
TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = 0x8C76
|
||||||
|
TRANSFORM_FEEDBACK_VARYINGS = 0x8C83
|
||||||
|
UNIFORM_ARRAY_STRIDE = 0x8A3C
|
||||||
|
UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x8A43
|
||||||
|
UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x8A42
|
||||||
|
UNIFORM_BLOCK_BINDING = 0x8A3F
|
||||||
|
UNIFORM_BLOCK_DATA_SIZE = 0x8A40
|
||||||
|
UNIFORM_BLOCK_INDEX = 0x8A3A
|
||||||
|
UNIFORM_BLOCK_NAME_LENGTH = 0x8A41
|
||||||
|
UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x8A46
|
||||||
|
UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x8A44
|
||||||
|
UNIFORM_BUFFER = 0x8A11
|
||||||
|
UNIFORM_BUFFER_BINDING = 0x8A28
|
||||||
|
UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34
|
||||||
|
UNIFORM_BUFFER_SIZE = 0x8A2A
|
||||||
|
UNIFORM_BUFFER_START = 0x8A29
|
||||||
|
UNIFORM_IS_ROW_MAJOR = 0x8A3E
|
||||||
|
UNIFORM_MATRIX_STRIDE = 0x8A3D
|
||||||
|
UNIFORM_NAME_LENGTH = 0x8A39
|
||||||
|
UNIFORM_OFFSET = 0x8A3B
|
||||||
|
UNIFORM_SIZE = 0x8A38
|
||||||
|
UNIFORM_TYPE = 0x8A37
|
||||||
|
UNPACK_IMAGE_HEIGHT = 0x806E
|
||||||
|
UNPACK_ROW_LENGTH = 0x0CF2
|
||||||
|
UNPACK_SKIP_IMAGES = 0x806D
|
||||||
|
UNPACK_SKIP_PIXELS = 0x0CF4
|
||||||
|
UNPACK_SKIP_ROWS = 0x0CF3
|
||||||
|
UNSIGNALED = 0x9118
|
||||||
|
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B
|
||||||
|
UNSIGNED_INT_2_10_10_10_REV = 0x8368
|
||||||
|
UNSIGNED_INT_24_8 = 0x84FA
|
||||||
|
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E
|
||||||
|
UNSIGNED_INT_SAMPLER_2D = 0x8DD2
|
||||||
|
UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x8DD7
|
||||||
|
UNSIGNED_INT_SAMPLER_3D = 0x8DD3
|
||||||
|
UNSIGNED_INT_SAMPLER_CUBE = 0x8DD4
|
||||||
|
UNSIGNED_INT_VEC2 = 0x8DC6
|
||||||
|
UNSIGNED_INT_VEC3 = 0x8DC7
|
||||||
|
UNSIGNED_INT_VEC4 = 0x8DC8
|
||||||
|
UNSIGNED_NORMALIZED = 0x8C17
|
||||||
|
VERTEX_ARRAY_BINDING = 0x85B5
|
||||||
|
VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE
|
||||||
|
VERTEX_ATTRIB_ARRAY_INTEGER = 0x88FD
|
||||||
|
WAIT_FAILED = 0x911D
|
||||||
|
)
|
||||||
+243
@@ -0,0 +1,243 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"debug/pe"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debug = log.New(ioutil.Discard, "gl: ", log.LstdFlags)
|
||||||
|
|
||||||
|
func downloadDLLs() (path string, err error) {
|
||||||
|
url := "https://dl.google.com/go/mobile/angle-bd3f8780b-" + runtime.GOARCH + ".tgz"
|
||||||
|
debug.Printf("downloading %s", url)
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("gl: %v", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
err2 := resp.Body.Close()
|
||||||
|
if err == nil && err2 != nil {
|
||||||
|
err = fmt.Errorf("gl: error reading body from %v: %v", url, err2)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
err := fmt.Errorf("gl: error fetching %v, status: %v", url, resp.Status)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := gzip.NewReader(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("gl: error reading gzip from %v: %v", url, err)
|
||||||
|
}
|
||||||
|
tr := tar.NewReader(r)
|
||||||
|
var bytesGLESv2, bytesEGL, bytesD3DCompiler []byte
|
||||||
|
for {
|
||||||
|
header, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("gl: error reading tar from %v: %v", url, err)
|
||||||
|
}
|
||||||
|
switch header.Name {
|
||||||
|
case "angle-" + runtime.GOARCH + "/libglesv2.dll":
|
||||||
|
bytesGLESv2, err = ioutil.ReadAll(tr)
|
||||||
|
case "angle-" + runtime.GOARCH + "/libegl.dll":
|
||||||
|
bytesEGL, err = ioutil.ReadAll(tr)
|
||||||
|
case "angle-" + runtime.GOARCH + "/d3dcompiler_47.dll":
|
||||||
|
bytesD3DCompiler, err = ioutil.ReadAll(tr)
|
||||||
|
default: // skip
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("gl: error reading %v from %v: %v", header.Name, url, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(bytesGLESv2) == 0 || len(bytesEGL) == 0 || len(bytesD3DCompiler) == 0 {
|
||||||
|
return "", fmt.Errorf("gl: did not find all DLLs in %v", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDLLs := func(path string) error {
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(path, "libglesv2.dll"), bytesGLESv2, 0755); err != nil {
|
||||||
|
return fmt.Errorf("gl: cannot install ANGLE: %v", err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(path, "libegl.dll"), bytesEGL, 0755); err != nil {
|
||||||
|
return fmt.Errorf("gl: cannot install ANGLE: %v", err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(filepath.Join(path, "d3dcompiler_47.dll"), bytesD3DCompiler, 0755); err != nil {
|
||||||
|
return fmt.Errorf("gl: cannot install ANGLE: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, we attempt to install these DLLs in LOCALAPPDATA/Shiny.
|
||||||
|
//
|
||||||
|
// Traditionally we would use the system32 directory, but it is
|
||||||
|
// no longer writable by normal programs.
|
||||||
|
os.MkdirAll(appdataPath(), 0775)
|
||||||
|
if err := writeDLLs(appdataPath()); err == nil {
|
||||||
|
return appdataPath(), nil
|
||||||
|
}
|
||||||
|
debug.Printf("DLLs could not be written to %s", appdataPath())
|
||||||
|
|
||||||
|
// Second, install in GOPATH/pkg if it exists.
|
||||||
|
gopath := os.Getenv("GOPATH")
|
||||||
|
gopathpkg := filepath.Join(gopath, "pkg")
|
||||||
|
if _, err := os.Stat(gopathpkg); err == nil && gopath != "" {
|
||||||
|
if err := writeDLLs(gopathpkg); err == nil {
|
||||||
|
return gopathpkg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug.Printf("DLLs could not be written to GOPATH")
|
||||||
|
|
||||||
|
// Third, pick a temporary directory.
|
||||||
|
tmp := os.TempDir()
|
||||||
|
if err := writeDLLs(tmp); err != nil {
|
||||||
|
return "", fmt.Errorf("gl: unable to install ANGLE DLLs: %v", err)
|
||||||
|
}
|
||||||
|
return tmp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appdataPath() string {
|
||||||
|
return filepath.Join(os.Getenv("LOCALAPPDATA"), "GoGL", runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsDLLs(dir string) bool {
|
||||||
|
compatible := func(name string) bool {
|
||||||
|
file, err := pe.Open(filepath.Join(dir, name))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
switch file.Machine {
|
||||||
|
case pe.IMAGE_FILE_MACHINE_AMD64:
|
||||||
|
return "amd64" == runtime.GOARCH
|
||||||
|
case pe.IMAGE_FILE_MACHINE_ARM:
|
||||||
|
return "arm" == runtime.GOARCH
|
||||||
|
case pe.IMAGE_FILE_MACHINE_I386:
|
||||||
|
return "386" == runtime.GOARCH
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return compatible("libglesv2.dll") && compatible("libegl.dll") && compatible("d3dcompiler_47.dll")
|
||||||
|
}
|
||||||
|
|
||||||
|
func chromePath() string {
|
||||||
|
// dlls are stored in:
|
||||||
|
// <BASE>/<VERSION>/libglesv2.dll
|
||||||
|
|
||||||
|
var installdirs = []string{
|
||||||
|
// Chrome User
|
||||||
|
filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome", "Application"),
|
||||||
|
// Chrome System
|
||||||
|
filepath.Join(os.Getenv("ProgramFiles(x86)"), "Google", "Chrome", "Application"),
|
||||||
|
// Chromium
|
||||||
|
filepath.Join(os.Getenv("LOCALAPPDATA"), "Chromium", "Application"),
|
||||||
|
// Chrome Canary
|
||||||
|
filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome SxS", "Application"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, installdir := range installdirs {
|
||||||
|
versiondirs, err := ioutil.ReadDir(installdir)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, versiondir := range versiondirs {
|
||||||
|
if !versiondir.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
versionpath := filepath.Join(installdir, versiondir.Name())
|
||||||
|
if containsDLLs(versionpath) {
|
||||||
|
return versionpath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func findDLLs() (err error) {
|
||||||
|
load := func(path string) (bool, error) {
|
||||||
|
if path != "" {
|
||||||
|
// don't try to start when one of the files is missing
|
||||||
|
if !containsDLLs(path) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
LibD3DCompiler.Name = filepath.Join(path, filepath.Base(LibD3DCompiler.Name))
|
||||||
|
LibGLESv2.Name = filepath.Join(path, filepath.Base(LibGLESv2.Name))
|
||||||
|
LibEGL.Name = filepath.Join(path, filepath.Base(LibEGL.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LibGLESv2.Load(); err == nil {
|
||||||
|
if err := LibEGL.Load(); err != nil {
|
||||||
|
return false, fmt.Errorf("gl: loaded libglesv2 but not libegl: %v", err)
|
||||||
|
}
|
||||||
|
if err := LibD3DCompiler.Load(); err != nil {
|
||||||
|
return false, fmt.Errorf("gl: loaded libglesv2, libegl but not d3dcompiler: %v", err)
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
debug.Printf("DLLs found")
|
||||||
|
} else {
|
||||||
|
debug.Printf("DLLs found in: %q", path)
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in the system directory.
|
||||||
|
if ok, err := load(""); ok || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in the AppData directory.
|
||||||
|
if ok, err := load(appdataPath()); ok || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a Chrome installation
|
||||||
|
if dir := chromePath(); dir != "" {
|
||||||
|
if ok, err := load(dir); ok || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in GOPATH/pkg.
|
||||||
|
if ok, err := load(filepath.Join(os.Getenv("GOPATH"), "pkg")); ok || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in temporary directory.
|
||||||
|
if ok, err := load(os.TempDir()); ok || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download the DLL binary.
|
||||||
|
path, err := downloadDLLs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
debug.Printf("DLLs written to %s", path)
|
||||||
|
if ok, err := load(path); !ok || err != nil {
|
||||||
|
return fmt.Errorf("gl: unable to load ANGLE after installation: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package gl implements Go bindings for OpenGL ES 2.0 and ES 3.0.
|
||||||
|
|
||||||
|
The GL functions are defined on a Context object that is responsible for
|
||||||
|
tracking a GL context. Typically a windowing system package (such as
|
||||||
|
golang.org/x/exp/shiny/screen) will call NewContext and provide
|
||||||
|
a gl.Context for a user application.
|
||||||
|
|
||||||
|
If the gl package is compiled on a platform capable of supporting ES 3.0,
|
||||||
|
the gl.Context object also implements gl.Context3.
|
||||||
|
|
||||||
|
The bindings are deliberately minimal, staying as close the C API as
|
||||||
|
possible. The semantics of each function maps onto functions
|
||||||
|
described in the Khronos documentation:
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# Debug Logging
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-tags gldebug
|
||||||
|
|
||||||
|
and each call to a GL function will log its input, output, and any
|
||||||
|
error messages. For example,
|
||||||
|
|
||||||
|
I/GoLog (27668): gl.GenBuffers(1) [Buffer(70001)]
|
||||||
|
I/GoLog (27668): gl.BindBuffer(ARRAY_BUFFER, Buffer(70001))
|
||||||
|
I/GoLog (27668): gl.BufferData(ARRAY_BUFFER, 36, len(36), STATIC_DRAW)
|
||||||
|
I/GoLog (27668): gl.BindBuffer(ARRAY_BUFFER, Buffer(70001))
|
||||||
|
I/GoLog (27668): gl.VertexAttribPointer(Attrib(0), 6, FLOAT, false, 0, 0) error: [INVALID_VALUE]
|
||||||
|
|
||||||
|
The gldebug tracing has very high overhead, so make sure to remove
|
||||||
|
the build tag before deploying any binaries.
|
||||||
|
*/
|
||||||
|
package gl // import "github.com/ebitengine/gomobile/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
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
type call struct {
|
||||||
|
args fnargs
|
||||||
|
parg unsafe.Pointer
|
||||||
|
blocking bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type fnargs struct {
|
||||||
|
fn glfn
|
||||||
|
|
||||||
|
a0 uintptr
|
||||||
|
a1 uintptr
|
||||||
|
a2 uintptr
|
||||||
|
a3 uintptr
|
||||||
|
a4 uintptr
|
||||||
|
a5 uintptr
|
||||||
|
a6 uintptr
|
||||||
|
a7 uintptr
|
||||||
|
a8 uintptr
|
||||||
|
a9 uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type glfn int
|
||||||
|
|
||||||
|
const (
|
||||||
|
glfnUNDEFINED glfn = iota
|
||||||
|
glfnActiveTexture
|
||||||
|
glfnAttachShader
|
||||||
|
glfnBindAttribLocation
|
||||||
|
glfnBindBuffer
|
||||||
|
glfnBindFramebuffer
|
||||||
|
glfnBindRenderbuffer
|
||||||
|
glfnBindTexture
|
||||||
|
glfnBindVertexArray
|
||||||
|
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
|
||||||
|
glfnDeleteVertexArray
|
||||||
|
glfnDepthFunc
|
||||||
|
glfnDepthRangef
|
||||||
|
glfnDepthMask
|
||||||
|
glfnDetachShader
|
||||||
|
glfnDisable
|
||||||
|
glfnDisableVertexAttribArray
|
||||||
|
glfnDrawArrays
|
||||||
|
glfnDrawElements
|
||||||
|
glfnEnable
|
||||||
|
glfnEnableVertexAttribArray
|
||||||
|
glfnFinish
|
||||||
|
glfnFlush
|
||||||
|
glfnFramebufferRenderbuffer
|
||||||
|
glfnFramebufferTexture2D
|
||||||
|
glfnFrontFace
|
||||||
|
glfnGenBuffer
|
||||||
|
glfnGenFramebuffer
|
||||||
|
glfnGenRenderbuffer
|
||||||
|
glfnGenTexture
|
||||||
|
glfnGenVertexArray
|
||||||
|
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
|
||||||
|
|
||||||
|
// ES 3.0 functions
|
||||||
|
glfnUniformMatrix2x3fv
|
||||||
|
glfnUniformMatrix3x2fv
|
||||||
|
glfnUniformMatrix2x4fv
|
||||||
|
glfnUniformMatrix4x2fv
|
||||||
|
glfnUniformMatrix3x4fv
|
||||||
|
glfnUniformMatrix4x3fv
|
||||||
|
glfnBlitFramebuffer
|
||||||
|
glfnUniform1ui
|
||||||
|
glfnUniform2ui
|
||||||
|
glfnUniform3ui
|
||||||
|
glfnUniform4ui
|
||||||
|
glfnUniform1uiv
|
||||||
|
glfnUniform2uiv
|
||||||
|
glfnUniform3uiv
|
||||||
|
glfnUniform4uiv
|
||||||
|
)
|
||||||
|
|
||||||
|
func goString(buf []byte) string {
|
||||||
|
for i, b := range buf {
|
||||||
|
if b == 0 {
|
||||||
|
return string(buf[:i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("buf is not NUL-terminated")
|
||||||
|
}
|
||||||
|
|
||||||
|
func glBoolean(b bool) uintptr {
|
||||||
|
if b {
|
||||||
|
return TRUE
|
||||||
|
}
|
||||||
|
return FALSE
|
||||||
|
}
|
||||||
+1851
File diff suppressed because it is too large
Load Diff
+3672
File diff suppressed because it is too large
Load Diff
+889
@@ -0,0 +1,889 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
// Context is an OpenGL ES context.
|
||||||
|
//
|
||||||
|
// A Context has a method for every GL function supported by ES 2 or later.
|
||||||
|
// In a program compiled with ES 3 support, a Context is also a Context3.
|
||||||
|
// For example, a program can:
|
||||||
|
//
|
||||||
|
// func f(glctx gl.Context) {
|
||||||
|
// glctx.(gl.Context3).BlitFramebuffer(...)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Contexts are independent. Two contexts can be used concurrently.
|
||||||
|
type Context interface {
|
||||||
|
// ActiveTexture sets the active texture unit.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glActiveTexture.xhtml
|
||||||
|
ActiveTexture(texture Enum)
|
||||||
|
|
||||||
|
// AttachShader attaches a shader to a program.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glAttachShader.xhtml
|
||||||
|
AttachShader(p Program, s Shader)
|
||||||
|
|
||||||
|
// BindAttribLocation binds a vertex attribute index with a named
|
||||||
|
// variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindAttribLocation.xhtml
|
||||||
|
BindAttribLocation(p Program, a Attrib, name string)
|
||||||
|
|
||||||
|
// BindBuffer binds a buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindBuffer.xhtml
|
||||||
|
BindBuffer(target Enum, b Buffer)
|
||||||
|
|
||||||
|
// BindFramebuffer binds a framebuffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindFramebuffer.xhtml
|
||||||
|
BindFramebuffer(target Enum, fb Framebuffer)
|
||||||
|
|
||||||
|
// BindRenderbuffer binds a render buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindRenderbuffer.xhtml
|
||||||
|
BindRenderbuffer(target Enum, rb Renderbuffer)
|
||||||
|
|
||||||
|
// BindTexture binds a texture.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindTexture.xhtml
|
||||||
|
BindTexture(target Enum, t Texture)
|
||||||
|
|
||||||
|
// BindVertexArray binds a vertex array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindVertexArray.xhtml
|
||||||
|
BindVertexArray(rb VertexArray)
|
||||||
|
|
||||||
|
// BlendColor sets the blend color.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendColor.xhtml
|
||||||
|
BlendColor(red, green, blue, alpha float32)
|
||||||
|
|
||||||
|
// BlendEquation sets both RGB and alpha blend equations.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendEquation.xhtml
|
||||||
|
BlendEquation(mode Enum)
|
||||||
|
|
||||||
|
// BlendEquationSeparate sets RGB and alpha blend equations separately.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendEquationSeparate.xhtml
|
||||||
|
BlendEquationSeparate(modeRGB, modeAlpha Enum)
|
||||||
|
|
||||||
|
// BlendFunc sets the pixel blending factors.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendFunc.xhtml
|
||||||
|
BlendFunc(sfactor, dfactor Enum)
|
||||||
|
|
||||||
|
// BlendFunc sets the pixel RGB and alpha blending factors separately.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendFuncSeparate.xhtml
|
||||||
|
BlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha Enum)
|
||||||
|
|
||||||
|
// BufferData creates a new data store for the bound buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBufferData.xhtml
|
||||||
|
BufferData(target Enum, src []byte, usage Enum)
|
||||||
|
|
||||||
|
// BufferInit creates a new uninitialized data store for the bound buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBufferData.xhtml
|
||||||
|
BufferInit(target Enum, size int, usage Enum)
|
||||||
|
|
||||||
|
// BufferSubData sets some of data in the bound buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glBufferSubData.xhtml
|
||||||
|
BufferSubData(target Enum, offset int, data []byte)
|
||||||
|
|
||||||
|
// CheckFramebufferStatus reports the completeness status of the
|
||||||
|
// active framebuffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCheckFramebufferStatus.xhtml
|
||||||
|
CheckFramebufferStatus(target Enum) Enum
|
||||||
|
|
||||||
|
// Clear clears the window.
|
||||||
|
//
|
||||||
|
// The behavior of Clear is influenced by the pixel ownership test,
|
||||||
|
// the scissor test, dithering, and the buffer writemasks.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glClear.xhtml
|
||||||
|
Clear(mask Enum)
|
||||||
|
|
||||||
|
// ClearColor specifies the RGBA values used to clear color buffers.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glClearColor.xhtml
|
||||||
|
ClearColor(red, green, blue, alpha float32)
|
||||||
|
|
||||||
|
// ClearDepthf sets the depth value used to clear the depth buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glClearDepthf.xhtml
|
||||||
|
ClearDepthf(d float32)
|
||||||
|
|
||||||
|
// ClearStencil sets the index used to clear the stencil buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glClearStencil.xhtml
|
||||||
|
ClearStencil(s int)
|
||||||
|
|
||||||
|
// ColorMask specifies whether color components in the framebuffer
|
||||||
|
// can be written.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glColorMask.xhtml
|
||||||
|
ColorMask(red, green, blue, alpha bool)
|
||||||
|
|
||||||
|
// CompileShader compiles the source code of s.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCompileShader.xhtml
|
||||||
|
CompileShader(s Shader)
|
||||||
|
|
||||||
|
// CompressedTexImage2D writes a compressed 2D texture.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexImage2D.xhtml
|
||||||
|
CompressedTexImage2D(target Enum, level int, internalformat Enum, width, height, border int, data []byte)
|
||||||
|
|
||||||
|
// CompressedTexSubImage2D writes a subregion of a compressed 2D texture.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexSubImage2D.xhtml
|
||||||
|
CompressedTexSubImage2D(target Enum, level, xoffset, yoffset, width, height int, format Enum, data []byte)
|
||||||
|
|
||||||
|
// CopyTexImage2D writes a 2D texture from the current framebuffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCopyTexImage2D.xhtml
|
||||||
|
CopyTexImage2D(target Enum, level int, internalformat Enum, x, y, width, height, border int)
|
||||||
|
|
||||||
|
// CopyTexSubImage2D writes a 2D texture subregion from the
|
||||||
|
// current framebuffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCopyTexSubImage2D.xhtml
|
||||||
|
CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, width, height int)
|
||||||
|
|
||||||
|
// CreateBuffer creates a buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenBuffers.xhtml
|
||||||
|
CreateBuffer() Buffer
|
||||||
|
|
||||||
|
// CreateFramebuffer creates a framebuffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenFramebuffers.xhtml
|
||||||
|
CreateFramebuffer() Framebuffer
|
||||||
|
|
||||||
|
// CreateProgram creates a new empty program object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCreateProgram.xhtml
|
||||||
|
CreateProgram() Program
|
||||||
|
|
||||||
|
// CreateRenderbuffer create a renderbuffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenRenderbuffers.xhtml
|
||||||
|
CreateRenderbuffer() Renderbuffer
|
||||||
|
|
||||||
|
// CreateShader creates a new empty shader object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCreateShader.xhtml
|
||||||
|
CreateShader(ty Enum) Shader
|
||||||
|
|
||||||
|
// CreateTexture creates a texture object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenTextures.xhtml
|
||||||
|
CreateTexture() Texture
|
||||||
|
|
||||||
|
// CreateTVertexArray creates a vertex array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenVertexArrays.xhtml
|
||||||
|
CreateVertexArray() VertexArray
|
||||||
|
|
||||||
|
// CullFace specifies which polygons are candidates for culling.
|
||||||
|
//
|
||||||
|
// Valid modes: FRONT, BACK, FRONT_AND_BACK.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glCullFace.xhtml
|
||||||
|
CullFace(mode Enum)
|
||||||
|
|
||||||
|
// DeleteBuffer deletes the given buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteBuffers.xhtml
|
||||||
|
DeleteBuffer(v Buffer)
|
||||||
|
|
||||||
|
// DeleteFramebuffer deletes the given framebuffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteFramebuffers.xhtml
|
||||||
|
DeleteFramebuffer(v Framebuffer)
|
||||||
|
|
||||||
|
// DeleteProgram deletes the given program object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteProgram.xhtml
|
||||||
|
DeleteProgram(p Program)
|
||||||
|
|
||||||
|
// DeleteRenderbuffer deletes the given render buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteRenderbuffers.xhtml
|
||||||
|
DeleteRenderbuffer(v Renderbuffer)
|
||||||
|
|
||||||
|
// DeleteShader deletes shader s.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteShader.xhtml
|
||||||
|
DeleteShader(s Shader)
|
||||||
|
|
||||||
|
// DeleteTexture deletes the given texture object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteTextures.xhtml
|
||||||
|
DeleteTexture(v Texture)
|
||||||
|
|
||||||
|
// DeleteVertexArray deletes the given render buffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteVertexArrays.xhtml
|
||||||
|
DeleteVertexArray(v VertexArray)
|
||||||
|
|
||||||
|
// DepthFunc sets the function used for depth buffer comparisons.
|
||||||
|
//
|
||||||
|
// Valid fn values:
|
||||||
|
// NEVER
|
||||||
|
// LESS
|
||||||
|
// EQUAL
|
||||||
|
// LEQUAL
|
||||||
|
// GREATER
|
||||||
|
// NOTEQUAL
|
||||||
|
// GEQUAL
|
||||||
|
// ALWAYS
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDepthFunc.xhtml
|
||||||
|
DepthFunc(fn Enum)
|
||||||
|
|
||||||
|
// DepthMask sets the depth buffer enabled for writing.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDepthMask.xhtml
|
||||||
|
DepthMask(flag bool)
|
||||||
|
|
||||||
|
// DepthRangef sets the mapping from normalized device coordinates to
|
||||||
|
// window coordinates.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDepthRangef.xhtml
|
||||||
|
DepthRangef(n, f float32)
|
||||||
|
|
||||||
|
// DetachShader detaches the shader s from the program p.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDetachShader.xhtml
|
||||||
|
DetachShader(p Program, s Shader)
|
||||||
|
|
||||||
|
// Disable disables various GL capabilities.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDisable.xhtml
|
||||||
|
Disable(cap Enum)
|
||||||
|
|
||||||
|
// DisableVertexAttribArray disables a vertex attribute array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDisableVertexAttribArray.xhtml
|
||||||
|
DisableVertexAttribArray(a Attrib)
|
||||||
|
|
||||||
|
// DrawArrays renders geometric primitives from the bound data.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDrawArrays.xhtml
|
||||||
|
DrawArrays(mode Enum, first, count int)
|
||||||
|
|
||||||
|
// DrawElements renders primitives from a bound buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glDrawElements.xhtml
|
||||||
|
DrawElements(mode Enum, count int, ty Enum, offset int)
|
||||||
|
|
||||||
|
// TODO(crawshaw): consider DrawElements8 / DrawElements16 / DrawElements32
|
||||||
|
|
||||||
|
// Enable enables various GL capabilities.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glEnable.xhtml
|
||||||
|
Enable(cap Enum)
|
||||||
|
|
||||||
|
// EnableVertexAttribArray enables a vertex attribute array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glEnableVertexAttribArray.xhtml
|
||||||
|
EnableVertexAttribArray(a Attrib)
|
||||||
|
|
||||||
|
// Finish blocks until the effects of all previously called GL
|
||||||
|
// commands are complete.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glFinish.xhtml
|
||||||
|
Finish()
|
||||||
|
|
||||||
|
// Flush empties all buffers. It does not block.
|
||||||
|
//
|
||||||
|
// An OpenGL implementation may buffer network communication,
|
||||||
|
// the command stream, or data inside the graphics accelerator.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glFlush.xhtml
|
||||||
|
Flush()
|
||||||
|
|
||||||
|
// FramebufferRenderbuffer attaches rb to the current frame buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glFramebufferRenderbuffer.xhtml
|
||||||
|
FramebufferRenderbuffer(target, attachment, rbTarget Enum, rb Renderbuffer)
|
||||||
|
|
||||||
|
// FramebufferTexture2D attaches the t to the current frame buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glFramebufferTexture2D.xhtml
|
||||||
|
FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int)
|
||||||
|
|
||||||
|
// FrontFace defines which polygons are front-facing.
|
||||||
|
//
|
||||||
|
// Valid modes: CW, CCW.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glFrontFace.xhtml
|
||||||
|
FrontFace(mode Enum)
|
||||||
|
|
||||||
|
// GenerateMipmap generates mipmaps for the current texture.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenerateMipmap.xhtml
|
||||||
|
GenerateMipmap(target Enum)
|
||||||
|
|
||||||
|
// GetActiveAttrib returns details about an active attribute variable.
|
||||||
|
// A value of 0 for index selects the first active attribute variable.
|
||||||
|
// Permissible values for index range from 0 to the number of active
|
||||||
|
// attribute variables minus 1.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveAttrib.xhtml
|
||||||
|
GetActiveAttrib(p Program, index uint32) (name string, size int, ty Enum)
|
||||||
|
|
||||||
|
// GetActiveUniform returns details about an active uniform variable.
|
||||||
|
// A value of 0 for index selects the first active uniform variable.
|
||||||
|
// Permissible values for index range from 0 to the number of active
|
||||||
|
// uniform variables minus 1.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveUniform.xhtml
|
||||||
|
GetActiveUniform(p Program, index uint32) (name string, size int, ty Enum)
|
||||||
|
|
||||||
|
// GetAttachedShaders returns the shader objects attached to program p.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetAttachedShaders.xhtml
|
||||||
|
GetAttachedShaders(p Program) []Shader
|
||||||
|
|
||||||
|
// GetAttribLocation returns the location of an attribute variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetAttribLocation.xhtml
|
||||||
|
GetAttribLocation(p Program, name string) Attrib
|
||||||
|
|
||||||
|
// GetBooleanv returns the boolean values of parameter pname.
|
||||||
|
//
|
||||||
|
// Many boolean parameters can be queried more easily using IsEnabled.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml
|
||||||
|
GetBooleanv(dst []bool, pname Enum)
|
||||||
|
|
||||||
|
// GetFloatv returns the float values of parameter pname.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml
|
||||||
|
GetFloatv(dst []float32, pname Enum)
|
||||||
|
|
||||||
|
// GetIntegerv returns the int values of parameter pname.
|
||||||
|
//
|
||||||
|
// Single values may be queried more easily using GetInteger.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml
|
||||||
|
GetIntegerv(dst []int32, pname Enum)
|
||||||
|
|
||||||
|
// GetInteger returns the int value of parameter pname.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml
|
||||||
|
GetInteger(pname Enum) int
|
||||||
|
|
||||||
|
// GetBufferParameteri returns a parameter for the active buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetBufferParameter.xhtml
|
||||||
|
GetBufferParameteri(target, value Enum) int
|
||||||
|
|
||||||
|
// GetError returns the next error.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetError.xhtml
|
||||||
|
GetError() Enum
|
||||||
|
|
||||||
|
// GetFramebufferAttachmentParameteri returns attachment parameters
|
||||||
|
// for the active framebuffer object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetFramebufferAttachmentParameteriv.xhtml
|
||||||
|
GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int
|
||||||
|
|
||||||
|
// GetProgrami returns a parameter value for a program.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetProgramiv.xhtml
|
||||||
|
GetProgrami(p Program, pname Enum) int
|
||||||
|
|
||||||
|
// GetProgramInfoLog returns the information log for a program.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetProgramInfoLog.xhtml
|
||||||
|
GetProgramInfoLog(p Program) string
|
||||||
|
|
||||||
|
// GetRenderbufferParameteri returns a parameter value for a render buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetRenderbufferParameteriv.xhtml
|
||||||
|
GetRenderbufferParameteri(target, pname Enum) int
|
||||||
|
|
||||||
|
// GetShaderi returns a parameter value for a shader.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderiv.xhtml
|
||||||
|
GetShaderi(s Shader, pname Enum) int
|
||||||
|
|
||||||
|
// GetShaderInfoLog returns the information log for a shader.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderInfoLog.xhtml
|
||||||
|
GetShaderInfoLog(s Shader) string
|
||||||
|
|
||||||
|
// GetShaderPrecisionFormat returns range and precision limits for
|
||||||
|
// shader types.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderPrecisionFormat.xhtml
|
||||||
|
GetShaderPrecisionFormat(shadertype, precisiontype Enum) (rangeLow, rangeHigh, precision int)
|
||||||
|
|
||||||
|
// GetShaderSource returns source code of shader s.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderSource.xhtml
|
||||||
|
GetShaderSource(s Shader) string
|
||||||
|
|
||||||
|
// GetString reports current GL state.
|
||||||
|
//
|
||||||
|
// Valid name values:
|
||||||
|
// EXTENSIONS
|
||||||
|
// RENDERER
|
||||||
|
// SHADING_LANGUAGE_VERSION
|
||||||
|
// VENDOR
|
||||||
|
// VERSION
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetString.xhtml
|
||||||
|
GetString(pname Enum) string
|
||||||
|
|
||||||
|
// GetTexParameterfv returns the float values of a texture parameter.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetTexParameter.xhtml
|
||||||
|
GetTexParameterfv(dst []float32, target, pname Enum)
|
||||||
|
|
||||||
|
// GetTexParameteriv returns the int values of a texture parameter.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetTexParameter.xhtml
|
||||||
|
GetTexParameteriv(dst []int32, target, pname Enum)
|
||||||
|
|
||||||
|
// GetUniformfv returns the float values of a uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniform.xhtml
|
||||||
|
GetUniformfv(dst []float32, src Uniform, p Program)
|
||||||
|
|
||||||
|
// GetUniformiv returns the float values of a uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniform.xhtml
|
||||||
|
GetUniformiv(dst []int32, src Uniform, p Program)
|
||||||
|
|
||||||
|
// GetUniformLocation returns the location of a uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniformLocation.xhtml
|
||||||
|
GetUniformLocation(p Program, name string) Uniform
|
||||||
|
|
||||||
|
// GetVertexAttribf reads the float value of a vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml
|
||||||
|
GetVertexAttribf(src Attrib, pname Enum) float32
|
||||||
|
|
||||||
|
// GetVertexAttribfv reads float values of a vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml
|
||||||
|
GetVertexAttribfv(dst []float32, src Attrib, pname Enum)
|
||||||
|
|
||||||
|
// GetVertexAttribi reads the int value of a vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml
|
||||||
|
GetVertexAttribi(src Attrib, pname Enum) int32
|
||||||
|
|
||||||
|
// GetVertexAttribiv reads int values of a vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml
|
||||||
|
GetVertexAttribiv(dst []int32, src Attrib, pname Enum)
|
||||||
|
|
||||||
|
// TODO(crawshaw): glGetVertexAttribPointerv
|
||||||
|
|
||||||
|
// Hint sets implementation-specific modes.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glHint.xhtml
|
||||||
|
Hint(target, mode Enum)
|
||||||
|
|
||||||
|
// IsBuffer reports if b is a valid buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsBuffer.xhtml
|
||||||
|
IsBuffer(b Buffer) bool
|
||||||
|
|
||||||
|
// IsEnabled reports if cap is an enabled capability.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsEnabled.xhtml
|
||||||
|
IsEnabled(cap Enum) bool
|
||||||
|
|
||||||
|
// IsFramebuffer reports if fb is a valid frame buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsFramebuffer.xhtml
|
||||||
|
IsFramebuffer(fb Framebuffer) bool
|
||||||
|
|
||||||
|
// IsProgram reports if p is a valid program object.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsProgram.xhtml
|
||||||
|
IsProgram(p Program) bool
|
||||||
|
|
||||||
|
// IsRenderbuffer reports if rb is a valid render buffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsRenderbuffer.xhtml
|
||||||
|
IsRenderbuffer(rb Renderbuffer) bool
|
||||||
|
|
||||||
|
// IsShader reports if s is valid shader.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsShader.xhtml
|
||||||
|
IsShader(s Shader) bool
|
||||||
|
|
||||||
|
// IsTexture reports if t is a valid texture.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glIsTexture.xhtml
|
||||||
|
IsTexture(t Texture) bool
|
||||||
|
|
||||||
|
// LineWidth specifies the width of lines.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glLineWidth.xhtml
|
||||||
|
LineWidth(width float32)
|
||||||
|
|
||||||
|
// LinkProgram links the specified program.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glLinkProgram.xhtml
|
||||||
|
LinkProgram(p Program)
|
||||||
|
|
||||||
|
// PixelStorei sets pixel storage parameters.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glPixelStorei.xhtml
|
||||||
|
PixelStorei(pname Enum, param int32)
|
||||||
|
|
||||||
|
// PolygonOffset sets the scaling factors for depth offsets.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glPolygonOffset.xhtml
|
||||||
|
PolygonOffset(factor, units float32)
|
||||||
|
|
||||||
|
// ReadPixels returns pixel data from a buffer.
|
||||||
|
//
|
||||||
|
// In GLES 3, the source buffer is controlled with ReadBuffer.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glReadPixels.xhtml
|
||||||
|
ReadPixels(dst []byte, x, y, width, height int, format, ty Enum)
|
||||||
|
|
||||||
|
// ReleaseShaderCompiler frees resources allocated by the shader compiler.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glReleaseShaderCompiler.xhtml
|
||||||
|
ReleaseShaderCompiler()
|
||||||
|
|
||||||
|
// RenderbufferStorage establishes the data storage, format, and
|
||||||
|
// dimensions of a renderbuffer object's image.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glRenderbufferStorage.xhtml
|
||||||
|
RenderbufferStorage(target, internalFormat Enum, width, height int)
|
||||||
|
|
||||||
|
// SampleCoverage sets multisample coverage parameters.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glSampleCoverage.xhtml
|
||||||
|
SampleCoverage(value float32, invert bool)
|
||||||
|
|
||||||
|
// Scissor defines the scissor box rectangle, in window coordinates.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glScissor.xhtml
|
||||||
|
Scissor(x, y, width, height int32)
|
||||||
|
|
||||||
|
// TODO(crawshaw): ShaderBinary
|
||||||
|
|
||||||
|
// ShaderSource sets the source code of s to the given source code.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glShaderSource.xhtml
|
||||||
|
ShaderSource(s Shader, src string)
|
||||||
|
|
||||||
|
// StencilFunc sets the front and back stencil test reference value.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilFunc.xhtml
|
||||||
|
StencilFunc(fn Enum, ref int, mask uint32)
|
||||||
|
|
||||||
|
// StencilFunc sets the front or back stencil test reference value.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilFuncSeparate.xhtml
|
||||||
|
StencilFuncSeparate(face, fn Enum, ref int, mask uint32)
|
||||||
|
|
||||||
|
// StencilMask controls the writing of bits in the stencil planes.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilMask.xhtml
|
||||||
|
StencilMask(mask uint32)
|
||||||
|
|
||||||
|
// StencilMaskSeparate controls the writing of bits in the stencil planes.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilMaskSeparate.xhtml
|
||||||
|
StencilMaskSeparate(face Enum, mask uint32)
|
||||||
|
|
||||||
|
// StencilOp sets front and back stencil test actions.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilOp.xhtml
|
||||||
|
StencilOp(fail, zfail, zpass Enum)
|
||||||
|
|
||||||
|
// StencilOpSeparate sets front or back stencil tests.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glStencilOpSeparate.xhtml
|
||||||
|
StencilOpSeparate(face, sfail, dpfail, dppass Enum)
|
||||||
|
|
||||||
|
// TexImage2D writes a 2D texture image.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexImage2D.xhtml
|
||||||
|
TexImage2D(target Enum, level int, internalFormat int, width, height int, format Enum, ty Enum, data []byte)
|
||||||
|
|
||||||
|
// TexSubImage2D writes a subregion of a 2D texture image.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexSubImage2D.xhtml
|
||||||
|
TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte)
|
||||||
|
|
||||||
|
// TexParameterf sets a float texture parameter.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml
|
||||||
|
TexParameterf(target, pname Enum, param float32)
|
||||||
|
|
||||||
|
// TexParameterfv sets a float texture parameter array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml
|
||||||
|
TexParameterfv(target, pname Enum, params []float32)
|
||||||
|
|
||||||
|
// TexParameteri sets an integer texture parameter.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml
|
||||||
|
TexParameteri(target, pname Enum, param int)
|
||||||
|
|
||||||
|
// TexParameteriv sets an integer texture parameter array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml
|
||||||
|
TexParameteriv(target, pname Enum, params []int32)
|
||||||
|
|
||||||
|
// Uniform1f writes a float uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform1f(dst Uniform, v float32)
|
||||||
|
|
||||||
|
// Uniform1fv writes a [len(src)]float uniform array.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform1fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// Uniform1i writes an int uniform variable.
|
||||||
|
//
|
||||||
|
// Uniform1i and Uniform1iv are the only two functions that may be used
|
||||||
|
// to load uniform variables defined as sampler types. Loading samplers
|
||||||
|
// with any other function will result in a INVALID_OPERATION error.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform1i(dst Uniform, v int)
|
||||||
|
|
||||||
|
// Uniform1iv writes a int uniform array of len(src) elements.
|
||||||
|
//
|
||||||
|
// Uniform1i and Uniform1iv are the only two functions that may be used
|
||||||
|
// to load uniform variables defined as sampler types. Loading samplers
|
||||||
|
// with any other function will result in a INVALID_OPERATION error.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform1iv(dst Uniform, src []int32)
|
||||||
|
|
||||||
|
// Uniform2f writes a vec2 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform2f(dst Uniform, v0, v1 float32)
|
||||||
|
|
||||||
|
// Uniform2fv writes a vec2 uniform array of len(src)/2 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform2fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// Uniform2i writes an ivec2 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform2i(dst Uniform, v0, v1 int)
|
||||||
|
|
||||||
|
// Uniform2iv writes an ivec2 uniform array of len(src)/2 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform2iv(dst Uniform, src []int32)
|
||||||
|
|
||||||
|
// Uniform3f writes a vec3 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform3f(dst Uniform, v0, v1, v2 float32)
|
||||||
|
|
||||||
|
// Uniform3fv writes a vec3 uniform array of len(src)/3 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform3fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// Uniform3i writes an ivec3 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform3i(dst Uniform, v0, v1, v2 int32)
|
||||||
|
|
||||||
|
// Uniform3iv writes an ivec3 uniform array of len(src)/3 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform3iv(dst Uniform, src []int32)
|
||||||
|
|
||||||
|
// Uniform4f writes a vec4 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform4f(dst Uniform, v0, v1, v2, v3 float32)
|
||||||
|
|
||||||
|
// Uniform4fv writes a vec4 uniform array of len(src)/4 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform4fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// Uniform4i writes an ivec4 uniform variable.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform4i(dst Uniform, v0, v1, v2, v3 int32)
|
||||||
|
|
||||||
|
// Uniform4i writes an ivec4 uniform array of len(src)/4 elements.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
Uniform4iv(dst Uniform, src []int32)
|
||||||
|
|
||||||
|
// UniformMatrix2fv writes 2x2 matrices. Each matrix uses four
|
||||||
|
// float32 values, so the number of matrices written is len(src)/4.
|
||||||
|
//
|
||||||
|
// Each matrix must be supplied in column major order.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
UniformMatrix2fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// UniformMatrix3fv writes 3x3 matrices. Each matrix uses nine
|
||||||
|
// float32 values, so the number of matrices written is len(src)/9.
|
||||||
|
//
|
||||||
|
// Each matrix must be supplied in column major order.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
UniformMatrix3fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// UniformMatrix4fv writes 4x4 matrices. Each matrix uses 16
|
||||||
|
// float32 values, so the number of matrices written is len(src)/16.
|
||||||
|
//
|
||||||
|
// Each matrix must be supplied in column major order.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml
|
||||||
|
UniformMatrix4fv(dst Uniform, src []float32)
|
||||||
|
|
||||||
|
// UseProgram sets the active program.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glUseProgram.xhtml
|
||||||
|
UseProgram(p Program)
|
||||||
|
|
||||||
|
// ValidateProgram checks to see whether the executables contained in
|
||||||
|
// program can execute given the current OpenGL state.
|
||||||
|
//
|
||||||
|
// Typically only used for debugging.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glValidateProgram.xhtml
|
||||||
|
ValidateProgram(p Program)
|
||||||
|
|
||||||
|
// VertexAttrib1f writes a float vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib1f(dst Attrib, x float32)
|
||||||
|
|
||||||
|
// VertexAttrib1fv writes a float vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib1fv(dst Attrib, src []float32)
|
||||||
|
|
||||||
|
// VertexAttrib2f writes a vec2 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib2f(dst Attrib, x, y float32)
|
||||||
|
|
||||||
|
// VertexAttrib2fv writes a vec2 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib2fv(dst Attrib, src []float32)
|
||||||
|
|
||||||
|
// VertexAttrib3f writes a vec3 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib3f(dst Attrib, x, y, z float32)
|
||||||
|
|
||||||
|
// VertexAttrib3fv writes a vec3 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib3fv(dst Attrib, src []float32)
|
||||||
|
|
||||||
|
// VertexAttrib4f writes a vec4 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib4f(dst Attrib, x, y, z, w float32)
|
||||||
|
|
||||||
|
// VertexAttrib4fv writes a vec4 vertex attribute.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml
|
||||||
|
VertexAttrib4fv(dst Attrib, src []float32)
|
||||||
|
|
||||||
|
// VertexAttribPointer uses a bound buffer to define vertex attribute data.
|
||||||
|
//
|
||||||
|
// Direct use of VertexAttribPointer to load data into OpenGL is not
|
||||||
|
// supported via the Go bindings. Instead, use BindBuffer with an
|
||||||
|
// ARRAY_BUFFER and then fill it using BufferData.
|
||||||
|
//
|
||||||
|
// The size argument specifies the number of components per attribute,
|
||||||
|
// between 1-4. The stride argument specifies the byte offset between
|
||||||
|
// consecutive vertex attributes.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttribPointer.xhtml
|
||||||
|
VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int)
|
||||||
|
|
||||||
|
// Viewport sets the viewport, an affine transformation that
|
||||||
|
// normalizes device coordinates to window coordinates.
|
||||||
|
//
|
||||||
|
// http://www.khronos.org/opengles/sdk/docs/man3/html/glViewport.xhtml
|
||||||
|
Viewport(x, y, width, height int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context3 is an OpenGL ES 3 context.
|
||||||
|
//
|
||||||
|
// When the gl package is compiled with GL ES 3 support, the produced
|
||||||
|
// Context object also implements the Context3 interface.
|
||||||
|
type Context3 interface {
|
||||||
|
Context
|
||||||
|
|
||||||
|
// BlitFramebuffer copies a block of pixels between framebuffers.
|
||||||
|
//
|
||||||
|
// https://www.khronos.org/opengles/sdk/docs/man3/html/glBlitFramebuffer.xhtml
|
||||||
|
BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1 int, mask uint, filter Enum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Worker is used by display driver code to execute OpenGL calls.
|
||||||
|
//
|
||||||
|
// Typically display driver code creates a gl.Context for an application,
|
||||||
|
// and along with it establishes a locked OS thread to execute the cgo
|
||||||
|
// calls:
|
||||||
|
//
|
||||||
|
// go func() {
|
||||||
|
// runtime.LockOSThread()
|
||||||
|
// // ... platform-specific cgo call to bind a C OpenGL context
|
||||||
|
// // into thread-local storage.
|
||||||
|
//
|
||||||
|
// glctx, worker := gl.NewContext()
|
||||||
|
// workAvailable := worker.WorkAvailable()
|
||||||
|
// go userAppCode(glctx)
|
||||||
|
// for {
|
||||||
|
// select {
|
||||||
|
// case <-workAvailable:
|
||||||
|
// worker.DoWork()
|
||||||
|
// case <-drawEvent:
|
||||||
|
// // ... platform-specific cgo call to draw screen
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
//
|
||||||
|
// This interface is an internal implementation detail and should only be used
|
||||||
|
// by the package responsible for managing the screen, such as
|
||||||
|
// github.com/ebitengine/gomobile/app.
|
||||||
|
type Worker interface {
|
||||||
|
// WorkAvailable returns a channel that communicates when DoWork should be
|
||||||
|
// called.
|
||||||
|
WorkAvailable() <-chan struct{}
|
||||||
|
|
||||||
|
// DoWork performs any pending OpenGL calls.
|
||||||
|
DoWork()
|
||||||
|
}
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build (darwin || linux || openbsd || windows) && gldebug
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
// Alternate versions of the types defined in types.go with extra
|
||||||
|
// debugging information attached. For documentation, see types.go.
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Enum uint32
|
||||||
|
|
||||||
|
type Attrib struct {
|
||||||
|
Value uint
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Program struct {
|
||||||
|
Init bool
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Shader struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Buffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Framebuffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Renderbuffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Texture struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Uniform struct {
|
||||||
|
Value int32
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VertexArray struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Attrib) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Enum) c() uintptr { return uintptr(v) }
|
||||||
|
func (v Program) c() uintptr {
|
||||||
|
if !v.Init {
|
||||||
|
ret := uintptr(0)
|
||||||
|
ret--
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return uintptr(v.Value)
|
||||||
|
}
|
||||||
|
func (v Shader) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Buffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Framebuffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Renderbuffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Texture) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Uniform) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v VertexArray) c() uintptr { return uintptr(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) }
|
||||||
|
func (v Shader) String() string { return fmt.Sprintf("Shader(%d)", v.Value) }
|
||||||
|
func (v Buffer) String() string { return fmt.Sprintf("Buffer(%d)", v.Value) }
|
||||||
|
func (v Framebuffer) String() string { return fmt.Sprintf("Framebuffer(%d)", v.Value) }
|
||||||
|
func (v Renderbuffer) String() string { return fmt.Sprintf("Renderbuffer(%d)", v.Value) }
|
||||||
|
func (v Texture) String() string { return fmt.Sprintf("Texture(%d)", v.Value) }
|
||||||
|
func (v Uniform) String() string { return fmt.Sprintf("Uniform(%d:%s)", v.Value, v.name) }
|
||||||
|
func (v VertexArray) String() string { return fmt.Sprintf("VertexArray(%d)", v.Value) }
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build (darwin || linux || openbsd || windows) && !gldebug
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Enum is equivalent to GLenum, and is normally used with one of the
|
||||||
|
// constants defined in this package.
|
||||||
|
type Enum uint32
|
||||||
|
|
||||||
|
// Types are defined a structs so that in debug mode they can carry
|
||||||
|
// extra information, such as a string name. See typesdebug.go.
|
||||||
|
|
||||||
|
// Attrib identifies the location of a specific attribute variable.
|
||||||
|
type Attrib struct {
|
||||||
|
Value uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program identifies a compiled shader program.
|
||||||
|
type Program struct {
|
||||||
|
// Init is set by CreateProgram, as some GL drivers (in particular,
|
||||||
|
// ANGLE) return true for glIsProgram(0).
|
||||||
|
Init bool
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shader identifies a GLSL shader.
|
||||||
|
type Shader struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer identifies a GL buffer object.
|
||||||
|
type Buffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Framebuffer identifies a GL framebuffer.
|
||||||
|
type Framebuffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Renderbuffer is a GL object that holds an image in an internal format.
|
||||||
|
type Renderbuffer struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Texture identifies a GL texture unit.
|
||||||
|
type Texture struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniform identifies the location of a specific uniform variable.
|
||||||
|
type Uniform struct {
|
||||||
|
Value int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// A VertexArray is a GL object that holds vertices in an internal format.
|
||||||
|
type VertexArray struct {
|
||||||
|
Value uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Attrib) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Enum) c() uintptr { return uintptr(v) }
|
||||||
|
func (v Program) c() uintptr {
|
||||||
|
if !v.Init {
|
||||||
|
ret := uintptr(0)
|
||||||
|
ret--
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return uintptr(v.Value)
|
||||||
|
}
|
||||||
|
func (v Shader) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Buffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Framebuffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Renderbuffer) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Texture) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v Uniform) c() uintptr { return uintptr(v.Value) }
|
||||||
|
func (v VertexArray) c() uintptr { return uintptr(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) }
|
||||||
|
func (v Shader) String() string { return fmt.Sprintf("Shader(%d)", v.Value) }
|
||||||
|
func (v Buffer) String() string { return fmt.Sprintf("Buffer(%d)", v.Value) }
|
||||||
|
func (v Framebuffer) String() string { return fmt.Sprintf("Framebuffer(%d)", v.Value) }
|
||||||
|
func (v Renderbuffer) String() string { return fmt.Sprintf("Renderbuffer(%d)", v.Value) }
|
||||||
|
func (v Texture) String() string { return fmt.Sprintf("Texture(%d)", v.Value) }
|
||||||
|
func (v Uniform) String() string { return fmt.Sprintf("Uniform(%d)", v.Value) }
|
||||||
|
func (v VertexArray) String() string { return fmt.Sprintf("VertexArray(%d)", v.Value) }
|
||||||
+557
@@ -0,0 +1,557 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin || linux || openbsd
|
||||||
|
// +build darwin linux openbsd
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "_cgo_export.h"
|
||||||
|
#include "work.h"
|
||||||
|
|
||||||
|
#if defined(GL_ES_VERSION_3_0) && GL_ES_VERSION_3_0
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
static void gles3missing() {
|
||||||
|
printf("GLES3 function is missing\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
static void glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { gles3missing(); }
|
||||||
|
static void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { gles3missing(); }
|
||||||
|
static void glUniform1ui(GLint location, GLuint v0) { gles3missing(); }
|
||||||
|
static void glUniform2ui(GLint location, GLuint v0, GLuint v1) { gles3missing(); }
|
||||||
|
static void glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { gles3missing(); }
|
||||||
|
static void glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { gles3missing(); }
|
||||||
|
static void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
|
||||||
|
static void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
|
||||||
|
static void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
|
||||||
|
static void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
|
||||||
|
static void glBindVertexArray(GLuint array) { gles3missing(); }
|
||||||
|
static void glGenVertexArrays(GLsizei n, GLuint *arrays) { gles3missing(); }
|
||||||
|
static void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) { gles3missing(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uintptr_t processFn(struct fnargs* args, char* parg) {
|
||||||
|
uintptr_t ret = 0;
|
||||||
|
switch (args->fn) {
|
||||||
|
case glfnUNDEFINED:
|
||||||
|
abort(); // bad glfn
|
||||||
|
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);
|
||||||
|
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 glfnBindVertexArray:
|
||||||
|
glBindVertexArray((GLenum)args->a0);
|
||||||
|
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 glfnBlitFramebuffer:
|
||||||
|
glBlitFramebuffer((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3, (GLint)args->a4, (GLint)args->a5, (GLint)args->a6, (GLint)args->a7, (GLbitfield)args->a8, (GLenum)args->a9);
|
||||||
|
break;
|
||||||
|
case glfnBufferData:
|
||||||
|
glBufferData((GLenum)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg, (GLenum)args->a2);
|
||||||
|
break;
|
||||||
|
case glfnBufferSubData:
|
||||||
|
glBufferSubData((GLenum)args->a0, (GLint)args->a1, (GLsizeiptr)args->a2, (GLvoid*)parg);
|
||||||
|
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*)parg);
|
||||||
|
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*)parg);
|
||||||
|
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 glfnDeleteVertexArray:
|
||||||
|
glDeleteVertexArrays(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 glfnGenVertexArray:
|
||||||
|
glGenVertexArrays(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*)&ret,
|
||||||
|
(GLenum*)args->a3,
|
||||||
|
(GLchar*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetActiveUniform:
|
||||||
|
glGetActiveUniform(
|
||||||
|
(GLuint)args->a0,
|
||||||
|
(GLuint)args->a1,
|
||||||
|
(GLsizei)args->a2,
|
||||||
|
NULL,
|
||||||
|
(GLint*)&ret,
|
||||||
|
(GLenum*)args->a3,
|
||||||
|
(GLchar*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetAttachedShaders:
|
||||||
|
glGetAttachedShaders((GLuint)args->a0, (GLsizei)args->a1, (GLsizei*)&ret, (GLuint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetAttribLocation:
|
||||||
|
ret = glGetAttribLocation((GLint)args->a0, (GLchar*)args->a1);
|
||||||
|
break;
|
||||||
|
case glfnGetBooleanv:
|
||||||
|
glGetBooleanv((GLenum)args->a0, (GLboolean*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetBufferParameteri:
|
||||||
|
glGetBufferParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)&ret);
|
||||||
|
break;
|
||||||
|
case glfnGetFloatv:
|
||||||
|
glGetFloatv((GLenum)args->a0, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetIntegerv:
|
||||||
|
glGetIntegerv((GLenum)args->a0, (GLint*)parg);
|
||||||
|
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, 0, (GLchar*)parg);
|
||||||
|
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, 0, (GLchar*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetShaderPrecisionFormat:
|
||||||
|
glGetShaderPrecisionFormat((GLenum)args->a0, (GLenum)args->a1, (GLint*)parg, &((GLint*)parg)[2]);
|
||||||
|
break;
|
||||||
|
case glfnGetShaderSource:
|
||||||
|
glGetShaderSource((GLuint)args->a0, (GLsizei)args->a1, 0, (GLchar*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetString:
|
||||||
|
ret = (uintptr_t)glGetString((GLenum)args->a0);
|
||||||
|
break;
|
||||||
|
case glfnGetTexParameterfv:
|
||||||
|
glGetTexParameterfv((GLenum)args->a0, (GLenum)args->a1, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetTexParameteriv:
|
||||||
|
glGetTexParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetUniformfv:
|
||||||
|
glGetUniformfv((GLuint)args->a0, (GLint)args->a1, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetUniformiv:
|
||||||
|
glGetUniformiv((GLuint)args->a0, (GLint)args->a1, (GLint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetUniformLocation:
|
||||||
|
ret = glGetUniformLocation((GLint)args->a0, (GLchar*)args->a1);
|
||||||
|
break;
|
||||||
|
case glfnGetVertexAttribfv:
|
||||||
|
glGetVertexAttribfv((GLuint)args->a0, (GLenum)args->a1, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnGetVertexAttribiv:
|
||||||
|
glGetVertexAttribiv((GLuint)args->a0, (GLenum)args->a1, (GLint*)parg);
|
||||||
|
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*)parg);
|
||||||
|
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_macos)
|
||||||
|
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
|
||||||
|
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*)parg);
|
||||||
|
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*)parg);
|
||||||
|
break;
|
||||||
|
case glfnTexParameterf:
|
||||||
|
glTexParameterf((GLenum)args->a0, (GLenum)args->a1, *(GLfloat*)&args->a2);
|
||||||
|
break;
|
||||||
|
case glfnTexParameterfv:
|
||||||
|
glTexParameterfv((GLenum)args->a0, (GLenum)args->a1, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnTexParameteri:
|
||||||
|
glTexParameteri((GLenum)args->a0, (GLenum)args->a1, (GLint)args->a2);
|
||||||
|
break;
|
||||||
|
case glfnTexParameteriv:
|
||||||
|
glTexParameteriv((GLenum)args->a0, (GLenum)args->a1, (GLint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform1f:
|
||||||
|
glUniform1f((GLint)args->a0, *(GLfloat*)&args->a1);
|
||||||
|
break;
|
||||||
|
case glfnUniform1fv:
|
||||||
|
glUniform1fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform1i:
|
||||||
|
glUniform1i((GLint)args->a0, (GLint)args->a1);
|
||||||
|
break;
|
||||||
|
case glfnUniform1ui:
|
||||||
|
glUniform1ui((GLint)args->a0, (GLuint)args->a1);
|
||||||
|
break;
|
||||||
|
case glfnUniform1uiv:
|
||||||
|
glUniform1uiv((GLint)args->a0, (GLsizeiptr)args->a1, (GLuint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform1iv:
|
||||||
|
glUniform1iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform2f:
|
||||||
|
glUniform2f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2);
|
||||||
|
break;
|
||||||
|
case glfnUniform2fv:
|
||||||
|
glUniform2fv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform2i:
|
||||||
|
glUniform2i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2);
|
||||||
|
break;
|
||||||
|
case glfnUniform2ui:
|
||||||
|
glUniform2ui((GLint)args->a0, (GLuint)args->a1, (GLuint)args->a2);
|
||||||
|
break;
|
||||||
|
case glfnUniform2uiv:
|
||||||
|
glUniform2uiv((GLint)args->a0, (GLsizeiptr)args->a1, (GLuint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform2iv:
|
||||||
|
glUniform2iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
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*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform3i:
|
||||||
|
glUniform3i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3);
|
||||||
|
break;
|
||||||
|
case glfnUniform3ui:
|
||||||
|
glUniform3ui((GLint)args->a0, (GLuint)args->a1, (GLuint)args->a2, (GLuint)args->a3);
|
||||||
|
break;
|
||||||
|
case glfnUniform3uiv:
|
||||||
|
glUniform3uiv((GLint)args->a0, (GLsizeiptr)args->a1, (GLuint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform3iv:
|
||||||
|
glUniform3iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
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*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform4i:
|
||||||
|
glUniform4i((GLint)args->a0, (GLint)args->a1, (GLint)args->a2, (GLint)args->a3, (GLint)args->a4);
|
||||||
|
break;
|
||||||
|
case glfnUniform4ui:
|
||||||
|
glUniform4ui((GLint)args->a0, (GLuint)args->a1, (GLuint)args->a2, (GLuint)args->a3, (GLuint)args->a4);
|
||||||
|
break;
|
||||||
|
case glfnUniform4uiv:
|
||||||
|
glUniform4uiv((GLint)args->a0, (GLsizeiptr)args->a1, (GLuint*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniform4iv:
|
||||||
|
glUniform4iv((GLint)args->a0, (GLsizeiptr)args->a1, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix2fv:
|
||||||
|
glUniformMatrix2fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix3fv:
|
||||||
|
glUniformMatrix3fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix4fv:
|
||||||
|
glUniformMatrix4fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix2x3fv:
|
||||||
|
glUniformMatrix2x3fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix3x2fv:
|
||||||
|
glUniformMatrix3x2fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix2x4fv:
|
||||||
|
glUniformMatrix2x4fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix4x2fv:
|
||||||
|
glUniformMatrix4x2fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix3x4fv:
|
||||||
|
glUniformMatrix3x4fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
break;
|
||||||
|
case glfnUniformMatrix4x3fv:
|
||||||
|
glUniformMatrix4x3fv((GLint)args->a0, (GLsizeiptr)args->a1, 0, (GLvoid*)parg);
|
||||||
|
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*)parg);
|
||||||
|
break;
|
||||||
|
case glfnVertexAttrib2f:
|
||||||
|
glVertexAttrib2f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2);
|
||||||
|
break;
|
||||||
|
case glfnVertexAttrib2fv:
|
||||||
|
glVertexAttrib2fv((GLint)args->a0, (GLfloat*)parg);
|
||||||
|
break;
|
||||||
|
case glfnVertexAttrib3f:
|
||||||
|
glVertexAttrib3f((GLint)args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
|
||||||
|
break;
|
||||||
|
case glfnVertexAttrib3fv:
|
||||||
|
glVertexAttrib3fv((GLint)args->a0, (GLfloat*)parg);
|
||||||
|
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*)parg);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
+173
@@ -0,0 +1,173 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build darwin || linux || openbsd
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo ios LDFLAGS: -framework OpenGLES
|
||||||
|
#cgo darwin,!ios LDFLAGS: -framework OpenGL
|
||||||
|
#cgo linux LDFLAGS: -lGLESv2
|
||||||
|
#cgo openbsd LDFLAGS: -L/usr/X11R6/lib/ -lGLESv2
|
||||||
|
|
||||||
|
#cgo android CFLAGS: -Dos_android
|
||||||
|
#cgo ios CFLAGS: -Dos_ios
|
||||||
|
#cgo darwin,!ios CFLAGS: -Dos_macos
|
||||||
|
#cgo darwin CFLAGS: -DGL_SILENCE_DEPRECATION -DGLES_SILENCE_DEPRECATION
|
||||||
|
#cgo linux CFLAGS: -Dos_linux
|
||||||
|
#cgo openbsd CFLAGS: -Dos_openbsd
|
||||||
|
|
||||||
|
#cgo openbsd CFLAGS: -I/usr/X11R6/include/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "work.h"
|
||||||
|
|
||||||
|
uintptr_t process(struct fnargs* cargs, char* parg0, char* parg1, char* parg2, int count) {
|
||||||
|
uintptr_t ret;
|
||||||
|
|
||||||
|
ret = processFn(&cargs[0], parg0);
|
||||||
|
if (count > 1) {
|
||||||
|
ret = processFn(&cargs[1], parg1);
|
||||||
|
}
|
||||||
|
if (count > 2) {
|
||||||
|
ret = processFn(&cargs[2], parg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
const workbufLen = 3
|
||||||
|
|
||||||
|
type context struct {
|
||||||
|
cptr uintptr
|
||||||
|
debug int32
|
||||||
|
|
||||||
|
workAvailable chan struct{}
|
||||||
|
|
||||||
|
// work is a queue of calls to execute.
|
||||||
|
work chan call
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// TODO: the comment above about concurrent calls isn't actually true: package
|
||||||
|
// app calls package gl, but it has to do so in a separate goroutine, which
|
||||||
|
// means that its gl calls (which may be blocking) can race with other gl calls
|
||||||
|
// in the main program. We should make it safe to issue blocking gl calls
|
||||||
|
// concurrently, or get the gl calls out of package app, or both.
|
||||||
|
retvalue chan C.uintptr_t
|
||||||
|
|
||||||
|
cargs [workbufLen]C.struct_fnargs
|
||||||
|
parg [workbufLen]*C.char
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) WorkAvailable() <-chan struct{} { return ctx.workAvailable }
|
||||||
|
|
||||||
|
type context3 struct {
|
||||||
|
*context
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext creates a cgo OpenGL context.
|
||||||
|
//
|
||||||
|
// See the Worker interface for more details on how it is used.
|
||||||
|
func NewContext() (Context, Worker) {
|
||||||
|
glctx := &context{
|
||||||
|
workAvailable: make(chan struct{}, 1),
|
||||||
|
work: make(chan call, workbufLen),
|
||||||
|
retvalue: make(chan C.uintptr_t),
|
||||||
|
}
|
||||||
|
if C.GLES_VERSION == "GL_ES_2_0" {
|
||||||
|
return glctx, glctx
|
||||||
|
}
|
||||||
|
return context3{glctx}, glctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns a GL ES version string, either "GL_ES_2_0" or "GL_ES_3_0".
|
||||||
|
// Future versions of the gl package may return "GL_ES_3_1".
|
||||||
|
func Version() string {
|
||||||
|
return C.GLES_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) enqueue(c call) uintptr {
|
||||||
|
ctx.work <- c
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ctx.workAvailable <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.blocking {
|
||||||
|
return uintptr(<-ctx.retvalue)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) DoWork() {
|
||||||
|
queue := make([]call, 0, workbufLen)
|
||||||
|
for {
|
||||||
|
// Wait until at least one piece of work is ready.
|
||||||
|
// Accumulate work until a piece is marked as blocking.
|
||||||
|
select {
|
||||||
|
case w := <-ctx.work:
|
||||||
|
queue = append(queue, w)
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
blocking := queue[len(queue)-1].blocking
|
||||||
|
enqueue:
|
||||||
|
for len(queue) < cap(queue) && !blocking {
|
||||||
|
select {
|
||||||
|
case w := <-ctx.work:
|
||||||
|
queue = append(queue, w)
|
||||||
|
blocking = queue[len(queue)-1].blocking
|
||||||
|
default:
|
||||||
|
break enqueue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the queued GL functions.
|
||||||
|
for i, q := range queue {
|
||||||
|
ctx.cargs[i] = *(*C.struct_fnargs)(unsafe.Pointer(&q.args))
|
||||||
|
ctx.parg[i] = (*C.char)(q.parg)
|
||||||
|
}
|
||||||
|
ret := C.process(&ctx.cargs[0], ctx.parg[0], ctx.parg[1], ctx.parg[2], C.int(len(queue)))
|
||||||
|
|
||||||
|
// Cleanup and signal.
|
||||||
|
queue = queue[:0]
|
||||||
|
if blocking {
|
||||||
|
ctx.retvalue <- ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if unsafe.Sizeof(C.GLint(0)) != unsafe.Sizeof(int32(0)) {
|
||||||
|
panic("GLint is not an int32")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cString creates C string off the Go heap.
|
||||||
|
// ret is a *char.
|
||||||
|
func (ctx *context) cString(str string) (uintptr, func()) {
|
||||||
|
ptr := unsafe.Pointer(C.CString(str))
|
||||||
|
return uintptr(ptr), func() { C.free(ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// cString creates a pointer to a C string off the Go heap.
|
||||||
|
// ret is a **char.
|
||||||
|
func (ctx *context) cStringPtr(str string) (uintptr, func()) {
|
||||||
|
s, free := ctx.cString(str)
|
||||||
|
ptr := C.malloc(C.size_t(unsafe.Sizeof((*int)(nil))))
|
||||||
|
*(*uintptr)(ptr) = s
|
||||||
|
return uintptr(ptr), func() {
|
||||||
|
free()
|
||||||
|
C.free(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
+217
@@ -0,0 +1,217 @@
|
|||||||
|
// 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_android
|
||||||
|
// TODO(crawshaw): We could include <android/api-level.h> and
|
||||||
|
// condition on __ANDROID_API__ to get GLES3 headers. However
|
||||||
|
// we also need to add -lGLESv3 to LDFLAGS, which we cannot do
|
||||||
|
// from inside an ifdef.
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#elif os_linux
|
||||||
|
#include <GLES3/gl3.h> // install on Ubuntu with: sudo apt-get install libegl1-mesa-dev libgles2-mesa-dev libx11-dev
|
||||||
|
#elif os_openbsd
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef os_ios
|
||||||
|
#include <OpenGLES/ES2/glext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef os_macos
|
||||||
|
#include <OpenGL/gl3.h>
|
||||||
|
#define GL_ES_VERSION_3_0 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GL_ES_VERSION_3_0) && GL_ES_VERSION_3_0
|
||||||
|
#define GLES_VERSION "GL_ES_3_0"
|
||||||
|
#else
|
||||||
|
#define GLES_VERSION "GL_ES_2_0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// TODO: generate this enum from fn.go.
|
||||||
|
typedef enum {
|
||||||
|
glfnUNDEFINED,
|
||||||
|
|
||||||
|
glfnActiveTexture,
|
||||||
|
glfnAttachShader,
|
||||||
|
glfnBindAttribLocation,
|
||||||
|
glfnBindBuffer,
|
||||||
|
glfnBindFramebuffer,
|
||||||
|
glfnBindRenderbuffer,
|
||||||
|
glfnBindTexture,
|
||||||
|
glfnBindVertexArray,
|
||||||
|
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,
|
||||||
|
glfnDeleteVertexArray,
|
||||||
|
glfnDepthFunc,
|
||||||
|
glfnDepthRangef,
|
||||||
|
glfnDepthMask,
|
||||||
|
glfnDetachShader,
|
||||||
|
glfnDisable,
|
||||||
|
glfnDisableVertexAttribArray,
|
||||||
|
glfnDrawArrays,
|
||||||
|
glfnDrawElements,
|
||||||
|
glfnEnable,
|
||||||
|
glfnEnableVertexAttribArray,
|
||||||
|
glfnFinish,
|
||||||
|
glfnFlush,
|
||||||
|
glfnFramebufferRenderbuffer,
|
||||||
|
glfnFramebufferTexture2D,
|
||||||
|
glfnFrontFace,
|
||||||
|
glfnGenBuffer,
|
||||||
|
glfnGenFramebuffer,
|
||||||
|
glfnGenRenderbuffer,
|
||||||
|
glfnGenTexture,
|
||||||
|
glfnGenVertexArray,
|
||||||
|
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,
|
||||||
|
|
||||||
|
// ES 3.0 functions
|
||||||
|
glfnUniformMatrix2x3fv,
|
||||||
|
glfnUniformMatrix3x2fv,
|
||||||
|
glfnUniformMatrix2x4fv,
|
||||||
|
glfnUniformMatrix4x2fv,
|
||||||
|
glfnUniformMatrix3x4fv,
|
||||||
|
glfnUniformMatrix4x3fv,
|
||||||
|
glfnBlitFramebuffer,
|
||||||
|
glfnUniform1ui,
|
||||||
|
glfnUniform2ui,
|
||||||
|
glfnUniform3ui,
|
||||||
|
glfnUniform4ui,
|
||||||
|
glfnUniform1uiv,
|
||||||
|
glfnUniform2uiv,
|
||||||
|
glfnUniform3uiv,
|
||||||
|
glfnUniform4uiv,
|
||||||
|
} glfn;
|
||||||
|
|
||||||
|
// TODO: generate this type from fn.go.
|
||||||
|
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;
|
||||||
|
uintptr_t a9;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern uintptr_t processFn(struct fnargs* args, char* parg);
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
//go:build (!cgo || (!darwin && !linux && !openbsd)) && !windows
|
||||||
|
|
||||||
|
package gl
|
||||||
|
|
||||||
|
// This file contains stub implementations of what the other work*.go files
|
||||||
|
// provide. These stubs don't do anything, other than compile (e.g. when cgo is
|
||||||
|
// disabled).
|
||||||
|
|
||||||
|
type context struct{}
|
||||||
|
|
||||||
|
func (*context) enqueue(c call) uintptr {
|
||||||
|
panic("unimplemented; GOOS/CGO combination not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*context) cString(str string) (uintptr, func()) {
|
||||||
|
panic("unimplemented; GOOS/CGO combination not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*context) cStringPtr(str string) (uintptr, func()) {
|
||||||
|
panic("unimplemented; GOOS/CGO combination not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
type context3 = context
|
||||||
|
|
||||||
|
func NewContext() (Context, Worker) {
|
||||||
|
panic("unimplemented; GOOS/CGO combination not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Version() string {
|
||||||
|
panic("unimplemented; GOOS/CGO combination not supported")
|
||||||
|
}
|
||||||
+569
@@ -0,0 +1,569 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// context is described in work.go.
|
||||||
|
type context struct {
|
||||||
|
debug int32
|
||||||
|
workAvailable chan struct{}
|
||||||
|
work chan call
|
||||||
|
retvalue chan uintptr
|
||||||
|
|
||||||
|
// TODO(crawshaw): will not work with a moving collector
|
||||||
|
cStringCounter int
|
||||||
|
cStrings map[int]unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) WorkAvailable() <-chan struct{} { return ctx.workAvailable }
|
||||||
|
|
||||||
|
type context3 struct {
|
||||||
|
*context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContext() (Context, Worker) {
|
||||||
|
if err := findDLLs(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
glctx := &context{
|
||||||
|
workAvailable: make(chan struct{}, 1),
|
||||||
|
work: make(chan call, 3),
|
||||||
|
retvalue: make(chan uintptr),
|
||||||
|
cStrings: make(map[int]unsafe.Pointer),
|
||||||
|
}
|
||||||
|
return glctx, glctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) enqueue(c call) uintptr {
|
||||||
|
ctx.work <- c
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ctx.workAvailable <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.blocking {
|
||||||
|
return <-ctx.retvalue
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) DoWork() {
|
||||||
|
// TODO: add a work queue
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case w := <-ctx.work:
|
||||||
|
ret := ctx.doWork(w)
|
||||||
|
if w.blocking {
|
||||||
|
ctx.retvalue <- ret
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) cString(s string) (uintptr, func()) {
|
||||||
|
buf := make([]byte, len(s)+1)
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
buf[i] = s[i]
|
||||||
|
}
|
||||||
|
ret := unsafe.Pointer(&buf[0])
|
||||||
|
id := ctx.cStringCounter
|
||||||
|
ctx.cStringCounter++
|
||||||
|
ctx.cStrings[id] = ret
|
||||||
|
return uintptr(ret), func() { delete(ctx.cStrings, id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *context) cStringPtr(str string) (uintptr, func()) {
|
||||||
|
s, sfree := ctx.cString(str)
|
||||||
|
sptr := [2]uintptr{s, 0}
|
||||||
|
ret := unsafe.Pointer(&sptr[0])
|
||||||
|
id := ctx.cStringCounter
|
||||||
|
ctx.cStringCounter++
|
||||||
|
ctx.cStrings[id] = ret
|
||||||
|
return uintptr(ret), func() { sfree(); delete(ctx.cStrings, id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixFloat copies the first four arguments into the XMM registers.
|
||||||
|
// This is for the windows/amd64 calling convention, that wants
|
||||||
|
// floating point arguments to be passed in XMM.
|
||||||
|
//
|
||||||
|
// Mercifully, type information is not required to implement
|
||||||
|
// this calling convention. In particular see the mixed int/float
|
||||||
|
// examples:
|
||||||
|
//
|
||||||
|
// https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
|
||||||
|
//
|
||||||
|
// This means it could be fixed in syscall.Syscall. The relevant
|
||||||
|
// issue is
|
||||||
|
//
|
||||||
|
// https://golang.org/issue/6510
|
||||||
|
func fixFloat(x0, x1, x2, x3 uintptr)
|
||||||
|
|
||||||
|
func (ctx *context) doWork(c call) (ret uintptr) {
|
||||||
|
if runtime.GOARCH == "amd64" {
|
||||||
|
fixFloat(c.args.a0, c.args.a1, c.args.a2, c.args.a3)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.args.fn {
|
||||||
|
case glfnActiveTexture:
|
||||||
|
syscall.Syscall(glActiveTexture.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnAttachShader:
|
||||||
|
syscall.Syscall(glAttachShader.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBindAttribLocation:
|
||||||
|
syscall.Syscall(glBindAttribLocation.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnBindBuffer:
|
||||||
|
syscall.Syscall(glBindBuffer.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBindFramebuffer:
|
||||||
|
syscall.Syscall(glBindFramebuffer.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBindRenderbuffer:
|
||||||
|
syscall.Syscall(glBindRenderbuffer.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBindTexture:
|
||||||
|
syscall.Syscall(glBindTexture.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBindVertexArray:
|
||||||
|
syscall.Syscall(glBindVertexArray.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnBlendColor:
|
||||||
|
syscall.Syscall6(glBlendColor.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnBlendEquation:
|
||||||
|
syscall.Syscall(glBlendEquation.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnBlendEquationSeparate:
|
||||||
|
syscall.Syscall(glBlendEquationSeparate.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBlendFunc:
|
||||||
|
syscall.Syscall(glBlendFunc.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnBlendFuncSeparate:
|
||||||
|
syscall.Syscall6(glBlendFuncSeparate.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnBufferData:
|
||||||
|
syscall.Syscall6(glBufferData.Addr(), 4, c.args.a0, c.args.a1, uintptr(c.parg), c.args.a2, 0, 0)
|
||||||
|
case glfnBufferSubData:
|
||||||
|
syscall.Syscall6(glBufferSubData.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnCheckFramebufferStatus:
|
||||||
|
ret, _, _ = syscall.Syscall(glCheckFramebufferStatus.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnClear:
|
||||||
|
syscall.Syscall(glClear.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnClearColor:
|
||||||
|
syscall.Syscall6(glClearColor.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnClearDepthf:
|
||||||
|
syscall.Syscall6(glClearDepthf.Addr(), 1, c.args.a0, 0, 0, 0, 0, 0)
|
||||||
|
case glfnClearStencil:
|
||||||
|
syscall.Syscall(glClearStencil.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnColorMask:
|
||||||
|
syscall.Syscall6(glColorMask.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnCompileShader:
|
||||||
|
syscall.Syscall(glCompileShader.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnCompressedTexImage2D:
|
||||||
|
syscall.Syscall9(glCompressedTexImage2D.Addr(), 8, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, c.args.a6, uintptr(c.parg), 0)
|
||||||
|
case glfnCompressedTexSubImage2D:
|
||||||
|
syscall.Syscall9(glCompressedTexSubImage2D.Addr(), 9, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, c.args.a6, c.args.a7, uintptr(c.parg))
|
||||||
|
case glfnCopyTexImage2D:
|
||||||
|
syscall.Syscall9(glCopyTexImage2D.Addr(), 8, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, c.args.a6, c.args.a7, 0)
|
||||||
|
case glfnCopyTexSubImage2D:
|
||||||
|
syscall.Syscall9(glCopyTexSubImage2D.Addr(), 8, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, c.args.a6, c.args.a7, 0)
|
||||||
|
case glfnCreateProgram:
|
||||||
|
ret, _, _ = syscall.Syscall(glCreateProgram.Addr(), 0, 0, 0, 0)
|
||||||
|
case glfnCreateShader:
|
||||||
|
ret, _, _ = syscall.Syscall(glCreateShader.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnCullFace:
|
||||||
|
syscall.Syscall(glCullFace.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDeleteBuffer:
|
||||||
|
syscall.Syscall(glDeleteBuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
|
||||||
|
case glfnDeleteFramebuffer:
|
||||||
|
syscall.Syscall(glDeleteFramebuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
|
||||||
|
case glfnDeleteProgram:
|
||||||
|
syscall.Syscall(glDeleteProgram.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDeleteRenderbuffer:
|
||||||
|
syscall.Syscall(glDeleteRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
|
||||||
|
case glfnDeleteShader:
|
||||||
|
syscall.Syscall(glDeleteShader.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDeleteVertexArray:
|
||||||
|
syscall.Syscall(glDeleteVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
|
||||||
|
case glfnDeleteTexture:
|
||||||
|
syscall.Syscall(glDeleteTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
|
||||||
|
case glfnDepthFunc:
|
||||||
|
syscall.Syscall(glDepthFunc.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDepthRangef:
|
||||||
|
syscall.Syscall6(glDepthRangef.Addr(), 2, c.args.a0, c.args.a1, 0, 0, 0, 0)
|
||||||
|
case glfnDepthMask:
|
||||||
|
syscall.Syscall(glDepthMask.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDetachShader:
|
||||||
|
syscall.Syscall(glDetachShader.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnDisable:
|
||||||
|
syscall.Syscall(glDisable.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDisableVertexAttribArray:
|
||||||
|
syscall.Syscall(glDisableVertexAttribArray.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnDrawArrays:
|
||||||
|
syscall.Syscall(glDrawArrays.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnDrawElements:
|
||||||
|
syscall.Syscall6(glDrawElements.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnEnable:
|
||||||
|
syscall.Syscall(glEnable.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnEnableVertexAttribArray:
|
||||||
|
syscall.Syscall(glEnableVertexAttribArray.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnFinish:
|
||||||
|
syscall.Syscall(glFinish.Addr(), 0, 0, 0, 0)
|
||||||
|
case glfnFlush:
|
||||||
|
syscall.Syscall(glFlush.Addr(), 0, 0, 0, 0)
|
||||||
|
case glfnFramebufferRenderbuffer:
|
||||||
|
syscall.Syscall6(glFramebufferRenderbuffer.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnFramebufferTexture2D:
|
||||||
|
syscall.Syscall6(glFramebufferTexture2D.Addr(), 5, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, 0)
|
||||||
|
case glfnFrontFace:
|
||||||
|
syscall.Syscall(glFrontFace.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnGenBuffer:
|
||||||
|
syscall.Syscall(glGenBuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
|
||||||
|
case glfnGenFramebuffer:
|
||||||
|
syscall.Syscall(glGenFramebuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
|
||||||
|
case glfnGenRenderbuffer:
|
||||||
|
syscall.Syscall(glGenRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
|
||||||
|
case glfnGenVertexArray:
|
||||||
|
syscall.Syscall(glGenVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
|
||||||
|
case glfnGenTexture:
|
||||||
|
syscall.Syscall(glGenTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
|
||||||
|
case glfnGenerateMipmap:
|
||||||
|
syscall.Syscall(glGenerateMipmap.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnGetActiveAttrib:
|
||||||
|
syscall.Syscall9(glGetActiveAttrib.Addr(), 7, c.args.a0, c.args.a1, c.args.a2, 0, uintptr(unsafe.Pointer(&ret)), c.args.a3, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetActiveUniform:
|
||||||
|
syscall.Syscall9(glGetActiveUniform.Addr(), 7, c.args.a0, c.args.a1, c.args.a2, 0, uintptr(unsafe.Pointer(&ret)), c.args.a3, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetAttachedShaders:
|
||||||
|
syscall.Syscall6(glGetAttachedShaders.Addr(), 4, c.args.a0, c.args.a1, uintptr(unsafe.Pointer(&ret)), uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetAttribLocation:
|
||||||
|
ret, _, _ = syscall.Syscall(glGetAttribLocation.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnGetBooleanv:
|
||||||
|
syscall.Syscall(glGetBooleanv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnGetBufferParameteri:
|
||||||
|
syscall.Syscall(glGetBufferParameteri.Addr(), 3, c.args.a0, c.args.a1, uintptr(unsafe.Pointer(&ret)))
|
||||||
|
case glfnGetError:
|
||||||
|
ret, _, _ = syscall.Syscall(glGetError.Addr(), 0, 0, 0, 0)
|
||||||
|
case glfnGetFloatv:
|
||||||
|
syscall.Syscall(glGetFloatv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnGetFramebufferAttachmentParameteriv:
|
||||||
|
syscall.Syscall6(glGetFramebufferAttachmentParameteriv.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, uintptr(unsafe.Pointer(&ret)), 0, 0)
|
||||||
|
case glfnGetIntegerv:
|
||||||
|
syscall.Syscall(glGetIntegerv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnGetProgramInfoLog:
|
||||||
|
syscall.Syscall6(glGetProgramInfoLog.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetProgramiv:
|
||||||
|
syscall.Syscall(glGetProgramiv.Addr(), 3, c.args.a0, c.args.a1, uintptr(unsafe.Pointer(&ret)))
|
||||||
|
case glfnGetRenderbufferParameteriv:
|
||||||
|
syscall.Syscall(glGetRenderbufferParameteriv.Addr(), 3, c.args.a0, c.args.a1, uintptr(unsafe.Pointer(&ret)))
|
||||||
|
case glfnGetShaderInfoLog:
|
||||||
|
syscall.Syscall6(glGetShaderInfoLog.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetShaderPrecisionFormat:
|
||||||
|
// c.parg is a [3]int32. The first [2]int32 of the array is one
|
||||||
|
// parameter, the final *int32 is another parameter.
|
||||||
|
syscall.Syscall6(glGetShaderPrecisionFormat.Addr(), 4, c.args.a0, c.args.a1, uintptr(c.parg), uintptr(c.parg)+2*unsafe.Sizeof(uintptr(0)), 0, 0)
|
||||||
|
case glfnGetShaderSource:
|
||||||
|
syscall.Syscall6(glGetShaderSource.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnGetShaderiv:
|
||||||
|
syscall.Syscall(glGetShaderiv.Addr(), 3, c.args.a0, c.args.a1, uintptr(unsafe.Pointer(&ret)))
|
||||||
|
case glfnGetString:
|
||||||
|
ret, _, _ = syscall.Syscall(glGetString.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnGetTexParameterfv:
|
||||||
|
syscall.Syscall(glGetTexParameterfv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnGetTexParameteriv:
|
||||||
|
syscall.Syscall(glGetTexParameteriv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnGetUniformLocation:
|
||||||
|
ret, _, _ = syscall.Syscall(glGetUniformLocation.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnGetUniformfv:
|
||||||
|
syscall.Syscall(glGetUniformfv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnGetUniformiv:
|
||||||
|
syscall.Syscall(glGetUniformiv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnGetVertexAttribfv:
|
||||||
|
syscall.Syscall(glGetVertexAttribfv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnGetVertexAttribiv:
|
||||||
|
syscall.Syscall(glGetVertexAttribiv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnHint:
|
||||||
|
syscall.Syscall(glHint.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnIsBuffer:
|
||||||
|
syscall.Syscall(glIsBuffer.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsEnabled:
|
||||||
|
syscall.Syscall(glIsEnabled.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsFramebuffer:
|
||||||
|
syscall.Syscall(glIsFramebuffer.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsProgram:
|
||||||
|
ret, _, _ = syscall.Syscall(glIsProgram.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsRenderbuffer:
|
||||||
|
syscall.Syscall(glIsRenderbuffer.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsShader:
|
||||||
|
syscall.Syscall(glIsShader.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnIsTexture:
|
||||||
|
syscall.Syscall(glIsTexture.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnLineWidth:
|
||||||
|
syscall.Syscall(glLineWidth.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnLinkProgram:
|
||||||
|
syscall.Syscall(glLinkProgram.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnPixelStorei:
|
||||||
|
syscall.Syscall(glPixelStorei.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnPolygonOffset:
|
||||||
|
syscall.Syscall6(glPolygonOffset.Addr(), 2, c.args.a0, c.args.a1, 0, 0, 0, 0)
|
||||||
|
case glfnReadPixels:
|
||||||
|
syscall.Syscall9(glReadPixels.Addr(), 7, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnReleaseShaderCompiler:
|
||||||
|
syscall.Syscall(glReleaseShaderCompiler.Addr(), 0, 0, 0, 0)
|
||||||
|
case glfnRenderbufferStorage:
|
||||||
|
syscall.Syscall6(glRenderbufferStorage.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnSampleCoverage:
|
||||||
|
syscall.Syscall6(glSampleCoverage.Addr(), 1, c.args.a0, 0, 0, 0, 0, 0)
|
||||||
|
case glfnScissor:
|
||||||
|
syscall.Syscall6(glScissor.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnShaderSource:
|
||||||
|
syscall.Syscall6(glShaderSource.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, 0, 0, 0)
|
||||||
|
case glfnStencilFunc:
|
||||||
|
syscall.Syscall(glStencilFunc.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnStencilFuncSeparate:
|
||||||
|
syscall.Syscall6(glStencilFuncSeparate.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnStencilMask:
|
||||||
|
syscall.Syscall(glStencilMask.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnStencilMaskSeparate:
|
||||||
|
syscall.Syscall(glStencilMaskSeparate.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnStencilOp:
|
||||||
|
syscall.Syscall(glStencilOp.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnStencilOpSeparate:
|
||||||
|
syscall.Syscall6(glStencilOpSeparate.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnTexImage2D:
|
||||||
|
syscall.Syscall9(glTexImage2D.Addr(), 9, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, 0, c.args.a5, c.args.a6, uintptr(c.parg))
|
||||||
|
case glfnTexParameterf:
|
||||||
|
syscall.Syscall6(glTexParameterf.Addr(), 3, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnTexParameterfv:
|
||||||
|
syscall.Syscall(glTexParameterfv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnTexParameteri:
|
||||||
|
syscall.Syscall(glTexParameteri.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnTexParameteriv:
|
||||||
|
syscall.Syscall(glTexParameteriv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnTexSubImage2D:
|
||||||
|
syscall.Syscall9(glTexSubImage2D.Addr(), 9, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5, c.args.a6, c.args.a7, uintptr(c.parg))
|
||||||
|
case glfnUniform1f:
|
||||||
|
syscall.Syscall6(glUniform1f.Addr(), 2, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnUniform1fv:
|
||||||
|
syscall.Syscall(glUniform1fv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform1i:
|
||||||
|
syscall.Syscall(glUniform1i.Addr(), 2, c.args.a0, c.args.a1, 0)
|
||||||
|
case glfnUniform1iv:
|
||||||
|
syscall.Syscall(glUniform1iv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform2f:
|
||||||
|
syscall.Syscall6(glUniform2f.Addr(), 3, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnUniform2fv:
|
||||||
|
syscall.Syscall(glUniform2fv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform2i:
|
||||||
|
syscall.Syscall(glUniform2i.Addr(), 3, c.args.a0, c.args.a1, c.args.a2)
|
||||||
|
case glfnUniform2iv:
|
||||||
|
syscall.Syscall(glUniform2iv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform3f:
|
||||||
|
syscall.Syscall6(glUniform3f.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnUniform3fv:
|
||||||
|
syscall.Syscall(glUniform3fv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform3i:
|
||||||
|
syscall.Syscall6(glUniform3i.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
case glfnUniform3iv:
|
||||||
|
syscall.Syscall(glUniform3iv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform4f:
|
||||||
|
syscall.Syscall6(glUniform4f.Addr(), 5, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnUniform4fv:
|
||||||
|
syscall.Syscall(glUniform4fv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniform4i:
|
||||||
|
syscall.Syscall6(glUniform4i.Addr(), 5, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, 0)
|
||||||
|
case glfnUniform4iv:
|
||||||
|
syscall.Syscall(glUniform4iv.Addr(), 3, c.args.a0, c.args.a1, uintptr(c.parg))
|
||||||
|
case glfnUniformMatrix2fv:
|
||||||
|
syscall.Syscall6(glUniformMatrix2fv.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnUniformMatrix3fv:
|
||||||
|
syscall.Syscall6(glUniformMatrix3fv.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnUniformMatrix4fv:
|
||||||
|
syscall.Syscall6(glUniformMatrix4fv.Addr(), 4, c.args.a0, c.args.a1, 0, uintptr(c.parg), 0, 0)
|
||||||
|
case glfnUseProgram:
|
||||||
|
syscall.Syscall(glUseProgram.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnValidateProgram:
|
||||||
|
syscall.Syscall(glValidateProgram.Addr(), 1, c.args.a0, 0, 0)
|
||||||
|
case glfnVertexAttrib1f:
|
||||||
|
syscall.Syscall6(glVertexAttrib1f.Addr(), 2, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnVertexAttrib1fv:
|
||||||
|
syscall.Syscall(glVertexAttrib1fv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnVertexAttrib2f:
|
||||||
|
syscall.Syscall6(glVertexAttrib2f.Addr(), 3, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnVertexAttrib2fv:
|
||||||
|
syscall.Syscall(glVertexAttrib2fv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnVertexAttrib3f:
|
||||||
|
syscall.Syscall6(glVertexAttrib3f.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnVertexAttrib3fv:
|
||||||
|
syscall.Syscall(glVertexAttrib3fv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnVertexAttrib4f:
|
||||||
|
syscall.Syscall6(glVertexAttrib4f.Addr(), 5, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnVertexAttrib4fv:
|
||||||
|
syscall.Syscall(glVertexAttrib4fv.Addr(), 2, c.args.a0, uintptr(c.parg), 0)
|
||||||
|
case glfnVertexAttribPointer:
|
||||||
|
syscall.Syscall6(glVertexAttribPointer.Addr(), 6, c.args.a0, c.args.a1, c.args.a2, c.args.a3, c.args.a4, c.args.a5)
|
||||||
|
case glfnViewport:
|
||||||
|
syscall.Syscall6(glViewport.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
|
||||||
|
default:
|
||||||
|
panic("unknown GL function")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported libraries for a Windows GUI driver.
|
||||||
|
//
|
||||||
|
// LibEGL is not used directly by the gl package, but is needed by any
|
||||||
|
// driver hoping to use OpenGL ES.
|
||||||
|
//
|
||||||
|
// LibD3DCompiler is needed by libglesv2.dll for compiling shaders.
|
||||||
|
var (
|
||||||
|
LibGLESv2 = syscall.NewLazyDLL("libglesv2.dll")
|
||||||
|
LibEGL = syscall.NewLazyDLL("libegl.dll")
|
||||||
|
LibD3DCompiler = syscall.NewLazyDLL("d3dcompiler_47.dll")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
libGLESv2 = LibGLESv2
|
||||||
|
glActiveTexture = libGLESv2.NewProc("glActiveTexture")
|
||||||
|
glAttachShader = libGLESv2.NewProc("glAttachShader")
|
||||||
|
glBindAttribLocation = libGLESv2.NewProc("glBindAttribLocation")
|
||||||
|
glBindBuffer = libGLESv2.NewProc("glBindBuffer")
|
||||||
|
glBindFramebuffer = libGLESv2.NewProc("glBindFramebuffer")
|
||||||
|
glBindRenderbuffer = libGLESv2.NewProc("glBindRenderbuffer")
|
||||||
|
glBindTexture = libGLESv2.NewProc("glBindTexture")
|
||||||
|
glBindVertexArray = libGLESv2.NewProc("glBindVertexArray")
|
||||||
|
glBlendColor = libGLESv2.NewProc("glBlendColor")
|
||||||
|
glBlendEquation = libGLESv2.NewProc("glBlendEquation")
|
||||||
|
glBlendEquationSeparate = libGLESv2.NewProc("glBlendEquationSeparate")
|
||||||
|
glBlendFunc = libGLESv2.NewProc("glBlendFunc")
|
||||||
|
glBlendFuncSeparate = libGLESv2.NewProc("glBlendFuncSeparate")
|
||||||
|
glBufferData = libGLESv2.NewProc("glBufferData")
|
||||||
|
glBufferSubData = libGLESv2.NewProc("glBufferSubData")
|
||||||
|
glCheckFramebufferStatus = libGLESv2.NewProc("glCheckFramebufferStatus")
|
||||||
|
glClear = libGLESv2.NewProc("glClear")
|
||||||
|
glClearColor = libGLESv2.NewProc("glClearColor")
|
||||||
|
glClearDepthf = libGLESv2.NewProc("glClearDepthf")
|
||||||
|
glClearStencil = libGLESv2.NewProc("glClearStencil")
|
||||||
|
glColorMask = libGLESv2.NewProc("glColorMask")
|
||||||
|
glCompileShader = libGLESv2.NewProc("glCompileShader")
|
||||||
|
glCompressedTexImage2D = libGLESv2.NewProc("glCompressedTexImage2D")
|
||||||
|
glCompressedTexSubImage2D = libGLESv2.NewProc("glCompressedTexSubImage2D")
|
||||||
|
glCopyTexImage2D = libGLESv2.NewProc("glCopyTexImage2D")
|
||||||
|
glCopyTexSubImage2D = libGLESv2.NewProc("glCopyTexSubImage2D")
|
||||||
|
glCreateProgram = libGLESv2.NewProc("glCreateProgram")
|
||||||
|
glCreateShader = libGLESv2.NewProc("glCreateShader")
|
||||||
|
glCullFace = libGLESv2.NewProc("glCullFace")
|
||||||
|
glDeleteBuffers = libGLESv2.NewProc("glDeleteBuffers")
|
||||||
|
glDeleteFramebuffers = libGLESv2.NewProc("glDeleteFramebuffers")
|
||||||
|
glDeleteProgram = libGLESv2.NewProc("glDeleteProgram")
|
||||||
|
glDeleteRenderbuffers = libGLESv2.NewProc("glDeleteRenderbuffers")
|
||||||
|
glDeleteShader = libGLESv2.NewProc("glDeleteShader")
|
||||||
|
glDeleteTextures = libGLESv2.NewProc("glDeleteTextures")
|
||||||
|
glDeleteVertexArrays = libGLESv2.NewProc("glDeleteVertexArrays")
|
||||||
|
glDepthFunc = libGLESv2.NewProc("glDepthFunc")
|
||||||
|
glDepthRangef = libGLESv2.NewProc("glDepthRangef")
|
||||||
|
glDepthMask = libGLESv2.NewProc("glDepthMask")
|
||||||
|
glDetachShader = libGLESv2.NewProc("glDetachShader")
|
||||||
|
glDisable = libGLESv2.NewProc("glDisable")
|
||||||
|
glDisableVertexAttribArray = libGLESv2.NewProc("glDisableVertexAttribArray")
|
||||||
|
glDrawArrays = libGLESv2.NewProc("glDrawArrays")
|
||||||
|
glDrawElements = libGLESv2.NewProc("glDrawElements")
|
||||||
|
glEnable = libGLESv2.NewProc("glEnable")
|
||||||
|
glEnableVertexAttribArray = libGLESv2.NewProc("glEnableVertexAttribArray")
|
||||||
|
glFinish = libGLESv2.NewProc("glFinish")
|
||||||
|
glFlush = libGLESv2.NewProc("glFlush")
|
||||||
|
glFramebufferRenderbuffer = libGLESv2.NewProc("glFramebufferRenderbuffer")
|
||||||
|
glFramebufferTexture2D = libGLESv2.NewProc("glFramebufferTexture2D")
|
||||||
|
glFrontFace = libGLESv2.NewProc("glFrontFace")
|
||||||
|
glGenBuffers = libGLESv2.NewProc("glGenBuffers")
|
||||||
|
glGenFramebuffers = libGLESv2.NewProc("glGenFramebuffers")
|
||||||
|
glGenRenderbuffers = libGLESv2.NewProc("glGenRenderbuffers")
|
||||||
|
glGenTextures = libGLESv2.NewProc("glGenTextures")
|
||||||
|
glGenVertexArrays = libGLESv2.NewProc("glGenVertexArrays")
|
||||||
|
glGenerateMipmap = libGLESv2.NewProc("glGenerateMipmap")
|
||||||
|
glGetActiveAttrib = libGLESv2.NewProc("glGetActiveAttrib")
|
||||||
|
glGetActiveUniform = libGLESv2.NewProc("glGetActiveUniform")
|
||||||
|
glGetAttachedShaders = libGLESv2.NewProc("glGetAttachedShaders")
|
||||||
|
glGetAttribLocation = libGLESv2.NewProc("glGetAttribLocation")
|
||||||
|
glGetBooleanv = libGLESv2.NewProc("glGetBooleanv")
|
||||||
|
glGetBufferParameteri = libGLESv2.NewProc("glGetBufferParameteri")
|
||||||
|
glGetError = libGLESv2.NewProc("glGetError")
|
||||||
|
glGetFloatv = libGLESv2.NewProc("glGetFloatv")
|
||||||
|
glGetFramebufferAttachmentParameteriv = libGLESv2.NewProc("glGetFramebufferAttachmentParameteriv")
|
||||||
|
glGetIntegerv = libGLESv2.NewProc("glGetIntegerv")
|
||||||
|
glGetProgramInfoLog = libGLESv2.NewProc("glGetProgramInfoLog")
|
||||||
|
glGetProgramiv = libGLESv2.NewProc("glGetProgramiv")
|
||||||
|
glGetRenderbufferParameteriv = libGLESv2.NewProc("glGetRenderbufferParameteriv")
|
||||||
|
glGetShaderInfoLog = libGLESv2.NewProc("glGetShaderInfoLog")
|
||||||
|
glGetShaderPrecisionFormat = libGLESv2.NewProc("glGetShaderPrecisionFormat")
|
||||||
|
glGetShaderSource = libGLESv2.NewProc("glGetShaderSource")
|
||||||
|
glGetShaderiv = libGLESv2.NewProc("glGetShaderiv")
|
||||||
|
glGetString = libGLESv2.NewProc("glGetString")
|
||||||
|
glGetTexParameterfv = libGLESv2.NewProc("glGetTexParameterfv")
|
||||||
|
glGetTexParameteriv = libGLESv2.NewProc("glGetTexParameteriv")
|
||||||
|
glGetUniformLocation = libGLESv2.NewProc("glGetUniformLocation")
|
||||||
|
glGetUniformfv = libGLESv2.NewProc("glGetUniformfv")
|
||||||
|
glGetUniformiv = libGLESv2.NewProc("glGetUniformiv")
|
||||||
|
glGetVertexAttribfv = libGLESv2.NewProc("glGetVertexAttribfv")
|
||||||
|
glGetVertexAttribiv = libGLESv2.NewProc("glGetVertexAttribiv")
|
||||||
|
glHint = libGLESv2.NewProc("glHint")
|
||||||
|
glIsBuffer = libGLESv2.NewProc("glIsBuffer")
|
||||||
|
glIsEnabled = libGLESv2.NewProc("glIsEnabled")
|
||||||
|
glIsFramebuffer = libGLESv2.NewProc("glIsFramebuffer")
|
||||||
|
glIsProgram = libGLESv2.NewProc("glIsProgram")
|
||||||
|
glIsRenderbuffer = libGLESv2.NewProc("glIsRenderbuffer")
|
||||||
|
glIsShader = libGLESv2.NewProc("glIsShader")
|
||||||
|
glIsTexture = libGLESv2.NewProc("glIsTexture")
|
||||||
|
glLineWidth = libGLESv2.NewProc("glLineWidth")
|
||||||
|
glLinkProgram = libGLESv2.NewProc("glLinkProgram")
|
||||||
|
glPixelStorei = libGLESv2.NewProc("glPixelStorei")
|
||||||
|
glPolygonOffset = libGLESv2.NewProc("glPolygonOffset")
|
||||||
|
glReadPixels = libGLESv2.NewProc("glReadPixels")
|
||||||
|
glReleaseShaderCompiler = libGLESv2.NewProc("glReleaseShaderCompiler")
|
||||||
|
glRenderbufferStorage = libGLESv2.NewProc("glRenderbufferStorage")
|
||||||
|
glSampleCoverage = libGLESv2.NewProc("glSampleCoverage")
|
||||||
|
glScissor = libGLESv2.NewProc("glScissor")
|
||||||
|
glShaderSource = libGLESv2.NewProc("glShaderSource")
|
||||||
|
glStencilFunc = libGLESv2.NewProc("glStencilFunc")
|
||||||
|
glStencilFuncSeparate = libGLESv2.NewProc("glStencilFuncSeparate")
|
||||||
|
glStencilMask = libGLESv2.NewProc("glStencilMask")
|
||||||
|
glStencilMaskSeparate = libGLESv2.NewProc("glStencilMaskSeparate")
|
||||||
|
glStencilOp = libGLESv2.NewProc("glStencilOp")
|
||||||
|
glStencilOpSeparate = libGLESv2.NewProc("glStencilOpSeparate")
|
||||||
|
glTexImage2D = libGLESv2.NewProc("glTexImage2D")
|
||||||
|
glTexParameterf = libGLESv2.NewProc("glTexParameterf")
|
||||||
|
glTexParameterfv = libGLESv2.NewProc("glTexParameterfv")
|
||||||
|
glTexParameteri = libGLESv2.NewProc("glTexParameteri")
|
||||||
|
glTexParameteriv = libGLESv2.NewProc("glTexParameteriv")
|
||||||
|
glTexSubImage2D = libGLESv2.NewProc("glTexSubImage2D")
|
||||||
|
glUniform1f = libGLESv2.NewProc("glUniform1f")
|
||||||
|
glUniform1fv = libGLESv2.NewProc("glUniform1fv")
|
||||||
|
glUniform1i = libGLESv2.NewProc("glUniform1i")
|
||||||
|
glUniform1iv = libGLESv2.NewProc("glUniform1iv")
|
||||||
|
glUniform2f = libGLESv2.NewProc("glUniform2f")
|
||||||
|
glUniform2fv = libGLESv2.NewProc("glUniform2fv")
|
||||||
|
glUniform2i = libGLESv2.NewProc("glUniform2i")
|
||||||
|
glUniform2iv = libGLESv2.NewProc("glUniform2iv")
|
||||||
|
glUniform3f = libGLESv2.NewProc("glUniform3f")
|
||||||
|
glUniform3fv = libGLESv2.NewProc("glUniform3fv")
|
||||||
|
glUniform3i = libGLESv2.NewProc("glUniform3i")
|
||||||
|
glUniform3iv = libGLESv2.NewProc("glUniform3iv")
|
||||||
|
glUniform4f = libGLESv2.NewProc("glUniform4f")
|
||||||
|
glUniform4fv = libGLESv2.NewProc("glUniform4fv")
|
||||||
|
glUniform4i = libGLESv2.NewProc("glUniform4i")
|
||||||
|
glUniform4iv = libGLESv2.NewProc("glUniform4iv")
|
||||||
|
glUniformMatrix2fv = libGLESv2.NewProc("glUniformMatrix2fv")
|
||||||
|
glUniformMatrix3fv = libGLESv2.NewProc("glUniformMatrix3fv")
|
||||||
|
glUniformMatrix4fv = libGLESv2.NewProc("glUniformMatrix4fv")
|
||||||
|
glUseProgram = libGLESv2.NewProc("glUseProgram")
|
||||||
|
glValidateProgram = libGLESv2.NewProc("glValidateProgram")
|
||||||
|
glVertexAttrib1f = libGLESv2.NewProc("glVertexAttrib1f")
|
||||||
|
glVertexAttrib1fv = libGLESv2.NewProc("glVertexAttrib1fv")
|
||||||
|
glVertexAttrib2f = libGLESv2.NewProc("glVertexAttrib2f")
|
||||||
|
glVertexAttrib2fv = libGLESv2.NewProc("glVertexAttrib2fv")
|
||||||
|
glVertexAttrib3f = libGLESv2.NewProc("glVertexAttrib3f")
|
||||||
|
glVertexAttrib3fv = libGLESv2.NewProc("glVertexAttrib3fv")
|
||||||
|
glVertexAttrib4f = libGLESv2.NewProc("glVertexAttrib4f")
|
||||||
|
glVertexAttrib4fv = libGLESv2.NewProc("glVertexAttrib4fv")
|
||||||
|
glVertexAttribPointer = libGLESv2.NewProc("glVertexAttribPointer")
|
||||||
|
glViewport = libGLESv2.NewProc("glViewport")
|
||||||
|
)
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2016 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 "textflag.h"
|
||||||
|
|
||||||
|
// fixFloat is unnecessary for windows/386
|
||||||
|
TEXT ·fixFloat(SB),NOSPLIT,$0-16
|
||||||
|
RET
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// 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 "textflag.h"
|
||||||
|
|
||||||
|
TEXT ·fixFloat(SB),NOSPLIT,$0-32
|
||||||
|
MOVQ x0+0(FP), X0
|
||||||
|
MOVQ x1+8(FP), X1
|
||||||
|
MOVQ x2+16(FP), X2
|
||||||
|
MOVQ x3+24(FP), X3
|
||||||
|
RET
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
// 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 mobileinit
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <jni.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static char* lockJNI(JavaVM *vm, uintptr_t* envp, int* attachedp) {
|
||||||
|
JNIEnv* env;
|
||||||
|
|
||||||
|
if (vm == NULL) {
|
||||||
|
return "no current JVM";
|
||||||
|
}
|
||||||
|
|
||||||
|
*attachedp = 0;
|
||||||
|
switch ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6)) {
|
||||||
|
case JNI_OK:
|
||||||
|
break;
|
||||||
|
case JNI_EDETACHED:
|
||||||
|
if ((*vm)->AttachCurrentThread(vm, &env, 0) != 0) {
|
||||||
|
return "cannot attach to JVM";
|
||||||
|
}
|
||||||
|
*attachedp = 1;
|
||||||
|
break;
|
||||||
|
case JNI_EVERSION:
|
||||||
|
return "bad JNI version";
|
||||||
|
default:
|
||||||
|
return "unknown JNI error from GetEnv";
|
||||||
|
}
|
||||||
|
|
||||||
|
*envp = (uintptr_t)env;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* checkException(uintptr_t jnienv) {
|
||||||
|
jthrowable exc;
|
||||||
|
JNIEnv* env = (JNIEnv*)jnienv;
|
||||||
|
|
||||||
|
if (!(*env)->ExceptionCheck(env)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
exc = (*env)->ExceptionOccurred(env);
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
|
||||||
|
jclass clazz = (*env)->FindClass(env, "java/lang/Throwable");
|
||||||
|
jmethodID toString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;");
|
||||||
|
jobject msgStr = (*env)->CallObjectMethod(env, exc, toString);
|
||||||
|
return (char*)(*env)->GetStringUTFChars(env, msgStr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlockJNI(JavaVM *vm) {
|
||||||
|
(*vm)->DetachCurrentThread(vm);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// currentVM is stored to initialize other cgo packages.
|
||||||
|
//
|
||||||
|
// As all the Go packages in a program form a single shared library,
|
||||||
|
// there can only be one JNI_OnLoad function for initialization. In
|
||||||
|
// OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available
|
||||||
|
// on android.
|
||||||
|
var currentVM *C.JavaVM
|
||||||
|
|
||||||
|
// currentCtx is Android's android.context.Context. May be NULL.
|
||||||
|
var currentCtx C.jobject
|
||||||
|
|
||||||
|
// SetCurrentContext populates the global Context object with the specified
|
||||||
|
// current JavaVM instance (vm) and android.context.Context object (ctx).
|
||||||
|
// The android.context.Context object must be a global reference.
|
||||||
|
func SetCurrentContext(vm unsafe.Pointer, ctx uintptr) {
|
||||||
|
currentVM = (*C.JavaVM)(vm)
|
||||||
|
currentCtx = (C.jobject)(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv.
|
||||||
|
//
|
||||||
|
// RunOnJVM blocks until the call to fn is complete. Any Java
|
||||||
|
// exception or failure to attach to the JVM is returned as an error.
|
||||||
|
//
|
||||||
|
// The function fn takes vm, the current JavaVM*,
|
||||||
|
// env, the current JNIEnv*, and
|
||||||
|
// ctx, a jobject representing the global android.context.Context.
|
||||||
|
func RunOnJVM(fn func(vm, env, ctx uintptr) error) error {
|
||||||
|
errch := make(chan error)
|
||||||
|
go func() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
env := C.uintptr_t(0)
|
||||||
|
attached := C.int(0)
|
||||||
|
if errStr := C.lockJNI(currentVM, &env, &attached); errStr != nil {
|
||||||
|
errch <- errors.New(C.GoString(errStr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if attached != 0 {
|
||||||
|
defer C.unlockJNI(currentVM)
|
||||||
|
}
|
||||||
|
|
||||||
|
vm := uintptr(unsafe.Pointer(currentVM))
|
||||||
|
if err := fn(vm, uintptr(env), uintptr(currentCtx)); err != nil {
|
||||||
|
errch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if exc := C.checkException(env); exc != nil {
|
||||||
|
errch <- errors.New(C.GoString(exc))
|
||||||
|
C.free(unsafe.Pointer(exc))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errch <- nil
|
||||||
|
}()
|
||||||
|
return <-errch
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 mobileinit contains common initialization logic for mobile platforms
|
||||||
|
// that is relevant to both all-Go apps and gobind-based apps.
|
||||||
|
//
|
||||||
|
// Long-term, some code in this package should consider moving into Go stdlib.
|
||||||
|
package mobileinit
|
||||||
|
|
||||||
|
import "C"
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package mobileinit
|
||||||
|
|
||||||
|
/*
|
||||||
|
To view the log output run:
|
||||||
|
adb logcat GoLog:I *:S
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Android redirects stdout and stderr to /dev/null.
|
||||||
|
// As these are common debugging utilities in Go,
|
||||||
|
// we redirect them to logcat.
|
||||||
|
//
|
||||||
|
// Unfortunately, logcat is line oriented, so we must buffer.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -landroid -llog
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctag = C.CString("GoLog")
|
||||||
|
// Store the writer end of the redirected stderr and stdout
|
||||||
|
// so that they are not garbage collected and closed.
|
||||||
|
stderr, stdout *os.File
|
||||||
|
)
|
||||||
|
|
||||||
|
type infoWriter struct{}
|
||||||
|
|
||||||
|
func (infoWriter) Write(p []byte) (n int, err error) {
|
||||||
|
cstr := C.CString(string(p))
|
||||||
|
C.__android_log_write(C.ANDROID_LOG_INFO, ctag, cstr)
|
||||||
|
C.free(unsafe.Pointer(cstr))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lineLog(f *os.File, priority C.int) {
|
||||||
|
const logSize = 1024 // matches android/log.h.
|
||||||
|
r := bufio.NewReaderSize(f, logSize)
|
||||||
|
for {
|
||||||
|
line, _, err := r.ReadLine()
|
||||||
|
str := string(line)
|
||||||
|
if err != nil {
|
||||||
|
str += " " + err.Error()
|
||||||
|
}
|
||||||
|
cstr := C.CString(str)
|
||||||
|
C.__android_log_write(priority, ctag, cstr)
|
||||||
|
C.free(unsafe.Pointer(cstr))
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetOutput(infoWriter{})
|
||||||
|
// android logcat includes all of log.LstdFlags
|
||||||
|
log.SetFlags(log.Flags() &^ log.LstdFlags)
|
||||||
|
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
stderr = w
|
||||||
|
if err := syscall.Dup3(int(w.Fd()), int(os.Stderr.Fd()), 0); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go lineLog(r, C.ANDROID_LOG_ERROR)
|
||||||
|
|
||||||
|
r, w, err = os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
stdout = w
|
||||||
|
if err := syscall.Dup3(int(w.Fd()), int(os.Stdout.Fd()), 0); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go lineLog(r, C.ANDROID_LOG_INFO)
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
// 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 mobileinit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <os/log.h>
|
||||||
|
|
||||||
|
os_log_t create_os_log() {
|
||||||
|
return os_log_create("org.golang.mobile", "os_log");
|
||||||
|
}
|
||||||
|
|
||||||
|
void os_log_wrap(os_log_t log, const char *str) {
|
||||||
|
os_log(log, "%s", str);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type osWriter struct {
|
||||||
|
w C.os_log_t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o osWriter) Write(p []byte) (n int, err error) {
|
||||||
|
cstr := C.CString(string(p))
|
||||||
|
C.os_log_wrap(o.w, cstr)
|
||||||
|
C.free(unsafe.Pointer(cstr))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetOutput(io.MultiWriter(os.Stderr, osWriter{C.create_os_log()}))
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*~
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
# HideConsole
|
||||||
|
|
||||||
|
Package hideconsole is a utility package to hide a console automatically even without `-ldflags "-Hwindowsgui"` on Windows.
|
||||||
|
|
||||||
|
On non-Windows, this package does nothing.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Import this package with a blank identifier.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
_ "github.com/ebitengine/hideconsole"
|
||||||
|
)
|
||||||
|
```
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
|
||||||
|
|
||||||
|
// Package hideconsole is a utility package to hide a console automatically
|
||||||
|
// even without `-ldflags "-Hwindowsgui"` on Windows.
|
||||||
|
//
|
||||||
|
// On non-Windows, this package does nothing.
|
||||||
|
//
|
||||||
|
// # Usage
|
||||||
|
//
|
||||||
|
// Import this package with a blank identifier:
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// _ "github.com/ebitengine/hideconsole"
|
||||||
|
// )
|
||||||
|
package hideconsole
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
|
||||||
|
|
||||||
|
package hideconsole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
user32 = windows.NewLazySystemDLL("user32.dll")
|
||||||
|
|
||||||
|
procFreeConsoleWindow = kernel32.NewProc("FreeConsole")
|
||||||
|
procGetConsoleWindow = kernel32.NewProc("GetConsoleWindow")
|
||||||
|
)
|
||||||
|
|
||||||
|
func freeConsole() error {
|
||||||
|
r, _, e := procFreeConsoleWindow.Call()
|
||||||
|
if int32(r) == 0 {
|
||||||
|
if e != nil && e != windows.ERROR_SUCCESS {
|
||||||
|
return fmt.Errorf("FreeConsole failed: %w", e)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("FreeConsole returned 0")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConsoleWindow() windows.HWND {
|
||||||
|
r, _, _ := procGetConsoleWindow.Call()
|
||||||
|
return windows.HWND(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hideConsoleWindow will hide the console window that is showing when
|
||||||
|
// compiling on Windows without specifying the '-ldflags "-Hwindowsgui"' flag.
|
||||||
|
func hideConsoleWindow() {
|
||||||
|
// In Xbox, GetWindowThreadProcessId might not exist.
|
||||||
|
if user32.NewProc("GetWindowThreadProcessId").Find() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pid := windows.GetCurrentProcessId()
|
||||||
|
|
||||||
|
// Get the process ID of the console's creator.
|
||||||
|
var cpid uint32
|
||||||
|
if _, err := windows.GetWindowThreadProcessId(getConsoleWindow(), &cpid); err != nil {
|
||||||
|
// Even if closing the console fails, this is not harmful.
|
||||||
|
// Ignore error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if pid == cpid {
|
||||||
|
// The current process created its own console. Hide this.
|
||||||
|
// Ignore error.
|
||||||
|
_ = freeConsole()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
hideConsoleWindow()
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
*~
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
# purego
|
||||||
|
[](https://pkg.go.dev/github.com/ebitengine/purego?GOOS=darwin)
|
||||||
|
|
||||||
|
A library for calling C functions from Go without Cgo.
|
||||||
|
|
||||||
|
> This is beta software so expect bugs and potentially API breaking changes
|
||||||
|
> but each release will be tagged to avoid breaking people's code.
|
||||||
|
> Bug reports are encouraged.
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
The [Ebitengine](https://github.com/hajimehoshi/ebiten) game engine was ported to use only Go on Windows. This enabled
|
||||||
|
cross-compiling to Windows from any other operating system simply by setting `GOOS=windows`. The purego project was
|
||||||
|
born to bring that same vision to the other platforms supported by Ebitengine.
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
- **Simple Cross-Compilation**: No C means you can build for other platforms easily without a C compiler.
|
||||||
|
- **Faster Compilation**: Efficiently cache your entirely Go builds.
|
||||||
|
- **Smaller Binaries**: Using Cgo generates a C wrapper function for each C function called. Purego doesn't!
|
||||||
|
- **Dynamic Linking**: Load symbols at runtime and use it as a plugin system.
|
||||||
|
- **Foreign Function Interface**: Call into other languages that are compiled into shared objects.
|
||||||
|
- **Cgo Fallback**: Works even with CGO_ENABLED=1 so incremental porting is possible.
|
||||||
|
This also means unsupported GOARCHs (freebsd/riscv64, linux/mips, etc.) will still work
|
||||||
|
except for float arguments and return values.
|
||||||
|
|
||||||
|
## Supported Platforms
|
||||||
|
|
||||||
|
- **FreeBSD**: amd64, arm64
|
||||||
|
- **Linux**: amd64, arm64
|
||||||
|
- **macOS / iOS**: amd64, arm64
|
||||||
|
- **Windows**: 386*, amd64, arm*, arm64
|
||||||
|
|
||||||
|
`*` These architectures only support SyscallN and NewCallback
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
This example only works on macOS and Linux. For a complete example look at [libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports Windows and FreeBSD.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/ebitengine/purego"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSystemLibrary() string {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
return "/usr/lib/libSystem.B.dylib"
|
||||||
|
case "linux":
|
||||||
|
return "libc.so.6"
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
libc, err := purego.Dlopen(getSystemLibrary(), purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var puts func(string)
|
||||||
|
purego.RegisterLibFunc(&puts, libc, "puts")
|
||||||
|
puts("Calling C from Go without Cgo!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then to run: `CGO_ENABLED=0 go run main.go`
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
If you have questions about how to incorporate purego in your project or want to discuss
|
||||||
|
how it works join the [Discord](https://discord.com/channels/842049801528016967/1123106378731487345)!
|
||||||
|
|
||||||
|
### External Code
|
||||||
|
|
||||||
|
Purego uses code that originates from the Go runtime. These files are under the BSD-3
|
||||||
|
License that can be found [in the Go Source](https://github.com/golang/go/blob/master/LICENSE).
|
||||||
|
This is a list of the copied files:
|
||||||
|
|
||||||
|
* `abi_*.h` from package `runtime/cgo`
|
||||||
|
* `zcallback_darwin_*.s` from package `runtime`
|
||||||
|
* `internal/fakecgo/abi_*.h` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/asm_GOARCH.s` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/callbacks.go` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/go_GOOS_GOARCH.go` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/iscgo.go` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/setenv.go` from package `runtime/cgo`
|
||||||
|
* `internal/fakecgo/freebsd.go` from package `runtime/cgo`
|
||||||
|
|
||||||
|
The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of
|
||||||
|
`#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636))
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
// Macros for transitioning from the host ABI to Go ABI0.
|
||||||
|
//
|
||||||
|
// These save the frame pointer, so in general, functions that use
|
||||||
|
// these should have zero frame size to suppress the automatic frame
|
||||||
|
// pointer, though it's harmless to not do this.
|
||||||
|
|
||||||
|
#ifdef GOOS_windows
|
||||||
|
|
||||||
|
// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
|
||||||
|
// PUSH_REGS_HOST_TO_ABI0.
|
||||||
|
#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
|
||||||
|
|
||||||
|
// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
|
||||||
|
// the host ABI to Go ABI0 code. It saves all registers that are
|
||||||
|
// callee-save in the host ABI and caller-save in Go ABI0 and prepares
|
||||||
|
// for entry to Go.
|
||||||
|
//
|
||||||
|
// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
|
||||||
|
// Clear the DF flag for the Go ABI.
|
||||||
|
// MXCSR matches the Go ABI, so we don't have to set that,
|
||||||
|
// and Go doesn't modify it, so we don't have to save it.
|
||||||
|
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||||
|
PUSHFQ \
|
||||||
|
CLD \
|
||||||
|
ADJSP $(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||||
|
MOVQ DI, (0*0)(SP) \
|
||||||
|
MOVQ SI, (1*8)(SP) \
|
||||||
|
MOVQ BP, (2*8)(SP) \
|
||||||
|
MOVQ BX, (3*8)(SP) \
|
||||||
|
MOVQ R12, (4*8)(SP) \
|
||||||
|
MOVQ R13, (5*8)(SP) \
|
||||||
|
MOVQ R14, (6*8)(SP) \
|
||||||
|
MOVQ R15, (7*8)(SP) \
|
||||||
|
MOVUPS X6, (8*8)(SP) \
|
||||||
|
MOVUPS X7, (10*8)(SP) \
|
||||||
|
MOVUPS X8, (12*8)(SP) \
|
||||||
|
MOVUPS X9, (14*8)(SP) \
|
||||||
|
MOVUPS X10, (16*8)(SP) \
|
||||||
|
MOVUPS X11, (18*8)(SP) \
|
||||||
|
MOVUPS X12, (20*8)(SP) \
|
||||||
|
MOVUPS X13, (22*8)(SP) \
|
||||||
|
MOVUPS X14, (24*8)(SP) \
|
||||||
|
MOVUPS X15, (26*8)(SP)
|
||||||
|
|
||||||
|
#define POP_REGS_HOST_TO_ABI0() \
|
||||||
|
MOVQ (0*0)(SP), DI \
|
||||||
|
MOVQ (1*8)(SP), SI \
|
||||||
|
MOVQ (2*8)(SP), BP \
|
||||||
|
MOVQ (3*8)(SP), BX \
|
||||||
|
MOVQ (4*8)(SP), R12 \
|
||||||
|
MOVQ (5*8)(SP), R13 \
|
||||||
|
MOVQ (6*8)(SP), R14 \
|
||||||
|
MOVQ (7*8)(SP), R15 \
|
||||||
|
MOVUPS (8*8)(SP), X6 \
|
||||||
|
MOVUPS (10*8)(SP), X7 \
|
||||||
|
MOVUPS (12*8)(SP), X8 \
|
||||||
|
MOVUPS (14*8)(SP), X9 \
|
||||||
|
MOVUPS (16*8)(SP), X10 \
|
||||||
|
MOVUPS (18*8)(SP), X11 \
|
||||||
|
MOVUPS (20*8)(SP), X12 \
|
||||||
|
MOVUPS (22*8)(SP), X13 \
|
||||||
|
MOVUPS (24*8)(SP), X14 \
|
||||||
|
MOVUPS (26*8)(SP), X15 \
|
||||||
|
ADJSP $-(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||||
|
POPFQ
|
||||||
|
|
||||||
|
#else
|
||||||
|
// SysV ABI
|
||||||
|
|
||||||
|
#define REGS_HOST_TO_ABI0_STACK (6*8)
|
||||||
|
|
||||||
|
// SysV MXCSR matches the Go ABI, so we don't have to set that,
|
||||||
|
// and Go doesn't modify it, so we don't have to save it.
|
||||||
|
// Both SysV and Go require DF to be cleared, so that's already clear.
|
||||||
|
// The SysV and Go frame pointer conventions are compatible.
|
||||||
|
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||||
|
ADJSP $(REGS_HOST_TO_ABI0_STACK) \
|
||||||
|
MOVQ BP, (5*8)(SP) \
|
||||||
|
LEAQ (5*8)(SP), BP \
|
||||||
|
MOVQ BX, (0*8)(SP) \
|
||||||
|
MOVQ R12, (1*8)(SP) \
|
||||||
|
MOVQ R13, (2*8)(SP) \
|
||||||
|
MOVQ R14, (3*8)(SP) \
|
||||||
|
MOVQ R15, (4*8)(SP)
|
||||||
|
|
||||||
|
#define POP_REGS_HOST_TO_ABI0() \
|
||||||
|
MOVQ (0*8)(SP), BX \
|
||||||
|
MOVQ (1*8)(SP), R12 \
|
||||||
|
MOVQ (2*8)(SP), R13 \
|
||||||
|
MOVQ (3*8)(SP), R14 \
|
||||||
|
MOVQ (4*8)(SP), R15 \
|
||||||
|
MOVQ (5*8)(SP), BP \
|
||||||
|
ADJSP $-(REGS_HOST_TO_ABI0_STACK)
|
||||||
|
|
||||||
|
#endif
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
// Macros for transitioning from the host ABI to Go ABI0.
|
||||||
|
//
|
||||||
|
// These macros save and restore the callee-saved registers
|
||||||
|
// from the stack, but they don't adjust stack pointer, so
|
||||||
|
// the user should prepare stack space in advance.
|
||||||
|
// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
|
||||||
|
// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
|
||||||
|
//
|
||||||
|
// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
|
||||||
|
// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
|
||||||
|
//
|
||||||
|
// R29 is not saved because Go will save and restore it.
|
||||||
|
|
||||||
|
#define SAVE_R19_TO_R28(offset) \
|
||||||
|
STP (R19, R20), ((offset)+0*8)(RSP) \
|
||||||
|
STP (R21, R22), ((offset)+2*8)(RSP) \
|
||||||
|
STP (R23, R24), ((offset)+4*8)(RSP) \
|
||||||
|
STP (R25, R26), ((offset)+6*8)(RSP) \
|
||||||
|
STP (R27, g), ((offset)+8*8)(RSP)
|
||||||
|
#define RESTORE_R19_TO_R28(offset) \
|
||||||
|
LDP ((offset)+0*8)(RSP), (R19, R20) \
|
||||||
|
LDP ((offset)+2*8)(RSP), (R21, R22) \
|
||||||
|
LDP ((offset)+4*8)(RSP), (R23, R24) \
|
||||||
|
LDP ((offset)+6*8)(RSP), (R25, R26) \
|
||||||
|
LDP ((offset)+8*8)(RSP), (R27, g) /* R28 */
|
||||||
|
#define SAVE_F8_TO_F15(offset) \
|
||||||
|
FSTPD (F8, F9), ((offset)+0*8)(RSP) \
|
||||||
|
FSTPD (F10, F11), ((offset)+2*8)(RSP) \
|
||||||
|
FSTPD (F12, F13), ((offset)+4*8)(RSP) \
|
||||||
|
FSTPD (F14, F15), ((offset)+6*8)(RSP)
|
||||||
|
#define RESTORE_F8_TO_F15(offset) \
|
||||||
|
FLDPD ((offset)+0*8)(RSP), (F8, F9) \
|
||||||
|
FLDPD ((offset)+2*8)(RSP), (F10, F11) \
|
||||||
|
FLDPD ((offset)+4*8)(RSP), (F12, F13) \
|
||||||
|
FLDPD ((offset)+6*8)(RSP), (F14, F15)
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build cgo && (darwin || freebsd || linux)
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// if CGO_ENABLED=1 import the Cgo runtime to ensure that it is set up properly.
|
||||||
|
// This is required since some frameworks need TLS setup the C way which Go doesn't do.
|
||||||
|
// We currently don't support ios in fakecgo mode so force Cgo or fail
|
||||||
|
// Even if CGO_ENABLED=1 the Cgo runtime is not imported unless `import "C"` is used.
|
||||||
|
// which will import this package automatically. Normally this isn't an issue since it
|
||||||
|
// usually isn't possible to call into C without using that import. However, with purego
|
||||||
|
// it is since we don't use `import "C"`!
|
||||||
|
import (
|
||||||
|
_ "runtime/cgo"
|
||||||
|
|
||||||
|
_ "github.com/ebitengine/purego/internal/cgo"
|
||||||
|
)
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// Dlerror represents an error value returned from Dlopen, Dlsym, or Dlclose.
|
||||||
|
type Dlerror struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Dlerror) Error() string {
|
||||||
|
return e.s
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unix Specification for dlfcn.h: https://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html
|
||||||
|
|
||||||
|
var (
|
||||||
|
fnDlopen func(path string, mode int) uintptr
|
||||||
|
fnDlsym func(handle uintptr, name string) uintptr
|
||||||
|
fnDlerror func() string
|
||||||
|
fnDlclose func(handle uintptr) bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterFunc(&fnDlopen, dlopenABI0)
|
||||||
|
RegisterFunc(&fnDlsym, dlsymABI0)
|
||||||
|
RegisterFunc(&fnDlerror, dlerrorABI0)
|
||||||
|
RegisterFunc(&fnDlclose, dlcloseABI0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dlopen examines the dynamic library or bundle file specified by path. If the file is compatible
|
||||||
|
// with the current process and has not already been loaded into the
|
||||||
|
// current process, it is loaded and linked. After being linked, if it contains
|
||||||
|
// any initializer functions, they are called, before Dlopen
|
||||||
|
// returns. It returns a handle that can be used with Dlsym and Dlclose.
|
||||||
|
// A second call to Dlopen with the same path will return the same handle, but the internal
|
||||||
|
// reference count for the handle will be incremented. Therefore, all
|
||||||
|
// Dlopen calls should be balanced with a Dlclose call.
|
||||||
|
func Dlopen(path string, mode int) (uintptr, error) {
|
||||||
|
u := fnDlopen(path, mode)
|
||||||
|
if u == 0 {
|
||||||
|
return 0, Dlerror{fnDlerror()}
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.
|
||||||
|
// It returns the address where that symbol is loaded into memory. If the symbol is not found,
|
||||||
|
// in the specified library or any of the libraries that were automatically loaded by Dlopen
|
||||||
|
// when that library was loaded, Dlsym returns zero.
|
||||||
|
func Dlsym(handle uintptr, name string) (uintptr, error) {
|
||||||
|
u := fnDlsym(handle, name)
|
||||||
|
if u == 0 {
|
||||||
|
return 0, Dlerror{fnDlerror()}
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dlclose decrements the reference count on the dynamic library handle.
|
||||||
|
// If the reference count drops to zero and no other loaded libraries
|
||||||
|
// use symbols in it, then the dynamic library is unloaded.
|
||||||
|
func Dlclose(handle uintptr) error {
|
||||||
|
if fnDlclose(handle) {
|
||||||
|
return Dlerror{fnDlerror()}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname openLibrary openLibrary
|
||||||
|
func openLibrary(name string) (uintptr, error) {
|
||||||
|
return Dlopen(name, RTLD_NOW|RTLD_GLOBAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadSymbol(handle uintptr, name string) (uintptr, error) {
|
||||||
|
return Dlsym(handle, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go
|
||||||
|
// the indirection is necessary because a function is actually a pointer to the pointer to the code.
|
||||||
|
// sadly, I do not know of anyway to remove the assembly stubs entirely because //go:linkname doesn't
|
||||||
|
// appear to work if you link directly to the C function on darwin arm64.
|
||||||
|
|
||||||
|
//go:linkname dlopen dlopen
|
||||||
|
var dlopen uintptr
|
||||||
|
var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen))
|
||||||
|
|
||||||
|
//go:linkname dlsym dlsym
|
||||||
|
var dlsym uintptr
|
||||||
|
var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym))
|
||||||
|
|
||||||
|
//go:linkname dlclose dlclose
|
||||||
|
var dlclose uintptr
|
||||||
|
var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose))
|
||||||
|
|
||||||
|
//go:linkname dlerror dlerror
|
||||||
|
var dlerror uintptr
|
||||||
|
var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror))
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// Source for constants: https://opensource.apple.com/source/dyld/dyld-360.14/include/dlfcn.h.auto.html
|
||||||
|
|
||||||
|
const (
|
||||||
|
RTLD_DEFAULT = ^uintptr(0) - 1 // Pseudo-handle for dlsym so search for any loaded symbol
|
||||||
|
RTLD_LAZY = 0x1 // Relocations are performed at an implementation-dependent time.
|
||||||
|
RTLD_NOW = 0x2 // Relocations are performed when the object is loaded.
|
||||||
|
RTLD_LOCAL = 0x4 // All symbols are not made available for relocation processing by other modules.
|
||||||
|
RTLD_GLOBAL = 0x8 // All symbols are available for relocation processing of other modules.
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_dlopen dlopen "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_dlopen dlopen "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// Constants as defined in https://github.com/freebsd/freebsd-src/blob/main/include/dlfcn.h
|
||||||
|
const (
|
||||||
|
RTLD_DEFAULT = ^uintptr(0) - 2 // Pseudo-handle for dlsym so search for any loaded symbol
|
||||||
|
RTLD_LAZY = 0x00001 // Relocations are performed at an implementation-dependent time.
|
||||||
|
RTLD_NOW = 0x00002 // Relocations are performed when the object is loaded.
|
||||||
|
RTLD_LOCAL = 0x00000 // All symbols are not made available for relocation processing by other modules.
|
||||||
|
RTLD_GLOBAL = 0x00100 // All symbols are available for relocation processing of other modules.
|
||||||
|
)
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// Source for constants: https://codebrowser.dev/glibc/glibc/bits/dlfcn.h.html
|
||||||
|
|
||||||
|
const (
|
||||||
|
RTLD_DEFAULT = 0x00000 // Pseudo-handle for dlsym so search for any loaded symbol
|
||||||
|
RTLD_LAZY = 0x00001 // Relocations are performed at an implementation-dependent time.
|
||||||
|
RTLD_NOW = 0x00002 // Relocations are performed when the object is loaded.
|
||||||
|
RTLD_LOCAL = 0x00000 // All symbols are not made available for relocation processing by other modules.
|
||||||
|
RTLD_GLOBAL = 0x00100 // All symbols are available for relocation processing of other modules.
|
||||||
|
)
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build !cgo
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_dlopen dlopen "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_dlsym dlsym "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_dlerror dlerror "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_dlclose dlclose "libc.so.7"
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build !cgo
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
// if there is no Cgo we must link to each of the functions from dlfcn.h
|
||||||
|
// then the functions are called inside dlfcn_stubs.s
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_dlopen dlopen "libdl.so.2"
|
||||||
|
//go:cgo_import_dynamic purego_dlsym dlsym "libdl.so.2"
|
||||||
|
//go:cgo_import_dynamic purego_dlerror dlerror "libdl.so.2"
|
||||||
|
//go:cgo_import_dynamic purego_dlclose dlclose "libdl.so.2"
|
||||||
|
|
||||||
|
// on amd64 we don't need the following line - on 386 we do...
|
||||||
|
// anyway - with those lines the output is better (but doesn't matter) - without it on amd64 we get multiple DT_NEEDED with "libc.so.6" etc
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic _ _ "libdl.so.2"
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || !cgo && (freebsd || linux)
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// func dlopen(path *byte, mode int) (ret uintptr)
|
||||||
|
TEXT dlopen(SB), NOSPLIT|NOFRAME, $0-0
|
||||||
|
JMP purego_dlopen(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func dlsym(handle uintptr, symbol *byte) (ret uintptr)
|
||||||
|
TEXT dlsym(SB), NOSPLIT|NOFRAME, $0-0
|
||||||
|
JMP purego_dlsym(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func dlerror() (ret *byte)
|
||||||
|
TEXT dlerror(SB), NOSPLIT|NOFRAME, $0-0
|
||||||
|
JMP purego_dlerror(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func dlclose(handle uintptr) (ret int)
|
||||||
|
TEXT dlclose(SB), NOSPLIT|NOFRAME, $0-0
|
||||||
|
JMP purego_dlclose(SB)
|
||||||
|
RET
|
||||||
+409
@@ -0,0 +1,409 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux || windows
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/ebitengine/purego/internal/strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
|
||||||
|
// It panics if it can't find the name symbol.
|
||||||
|
func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||||
|
sym, err := loadSymbol(handle, name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
RegisterFunc(fptr, sym)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterFunc takes a pointer to a Go function representing the calling convention of the C function.
|
||||||
|
// fptr will be set to a function that when called will call the C function given by cfn with the
|
||||||
|
// parameters passed in the correct registers and stack.
|
||||||
|
//
|
||||||
|
// A panic is produced if the type is not a function pointer or if the function returns more than 1 value.
|
||||||
|
//
|
||||||
|
// These conversions describe how a Go type in the fptr will be used to call
|
||||||
|
// the C function. It is important to note that there is no way to verify that fptr
|
||||||
|
// matches the C function. This also holds true for struct types where the padding
|
||||||
|
// needs to be ensured to match that of C; RegisterFunc does not verify this.
|
||||||
|
//
|
||||||
|
// # Type Conversions (Go <=> C)
|
||||||
|
//
|
||||||
|
// string <=> char*
|
||||||
|
// bool <=> _Bool
|
||||||
|
// uintptr <=> uintptr_t
|
||||||
|
// uint <=> uint32_t or uint64_t
|
||||||
|
// uint8 <=> uint8_t
|
||||||
|
// uint16 <=> uint16_t
|
||||||
|
// uint32 <=> uint32_t
|
||||||
|
// uint64 <=> uint64_t
|
||||||
|
// int <=> int32_t or int64_t
|
||||||
|
// int8 <=> int8_t
|
||||||
|
// int16 <=> int16_t
|
||||||
|
// int32 <=> int32_t
|
||||||
|
// int64 <=> int64_t
|
||||||
|
// float32 <=> float
|
||||||
|
// float64 <=> double
|
||||||
|
// struct <=> struct (WIP - darwin only)
|
||||||
|
// func <=> C function
|
||||||
|
// unsafe.Pointer, *T <=> void*
|
||||||
|
// []T => void*
|
||||||
|
//
|
||||||
|
// There is a special case when the last argument of fptr is a variadic interface (or []interface}
|
||||||
|
// it will be expanded into a call to the C function as if it had the arguments in that slice.
|
||||||
|
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
|
||||||
|
// This is not the same as C variadic.
|
||||||
|
//
|
||||||
|
// # Memory
|
||||||
|
//
|
||||||
|
// In general it is not possible for purego to guarantee the lifetimes of objects returned or received from
|
||||||
|
// calling functions using RegisterFunc. For arguments to a C function it is important that the C function doesn't
|
||||||
|
// hold onto a reference to Go memory. This is the same as the [Cgo rules].
|
||||||
|
//
|
||||||
|
// However, there are some special cases. When passing a string as an argument if the string does not end in a null
|
||||||
|
// terminated byte (\x00) then the string will be copied into memory maintained by purego. The memory is only valid for
|
||||||
|
// that specific call. Therefore, if the C code keeps a reference to that string it may become invalid at some
|
||||||
|
// undefined time. However, if the string does already contain a null-terminated byte then no copy is done.
|
||||||
|
// It is then the responsibility of the caller to ensure the string stays alive as long as it's needed in C memory.
|
||||||
|
// This can be done using runtime.KeepAlive or allocating the string in C memory using malloc. When a C function
|
||||||
|
// returns a null-terminated pointer to char a Go string can be used. Purego will allocate a new string in Go memory
|
||||||
|
// and copy the data over. This string will be garbage collected whenever Go decides it's no longer referenced.
|
||||||
|
// This C created string will not be freed by purego. If the pointer to char is not null-terminated or must continue
|
||||||
|
// to point to C memory (because it's a buffer for example) then use a pointer to byte and then convert that to a slice
|
||||||
|
// using unsafe.Slice. Doing this means that it becomes the responsibility of the caller to care about the lifetime
|
||||||
|
// of the pointer
|
||||||
|
//
|
||||||
|
// # Structs
|
||||||
|
//
|
||||||
|
// Purego can handle the most common structs that have fields of builtin types like int8, uint16, float32, etc. However,
|
||||||
|
// it does not support aligning fields properly. It is therefore the responsibility of the caller to ensure
|
||||||
|
// that all padding is added to the Go struct to match the C one. See `BoolStructFn` in struct_test.go for an example.
|
||||||
|
//
|
||||||
|
// # Example
|
||||||
|
//
|
||||||
|
// All functions below call this C function:
|
||||||
|
//
|
||||||
|
// char *foo(char *str);
|
||||||
|
//
|
||||||
|
// // Let purego convert types
|
||||||
|
// var foo func(s string) string
|
||||||
|
// goString := foo("copied")
|
||||||
|
// // Go will garbage collect this string
|
||||||
|
//
|
||||||
|
// // Manually, handle allocations
|
||||||
|
// var foo2 func(b string) *byte
|
||||||
|
// mustFree := foo2("not copied\x00")
|
||||||
|
// defer free(mustFree)
|
||||||
|
//
|
||||||
|
// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
|
||||||
|
func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||||
|
fn := reflect.ValueOf(fptr).Elem()
|
||||||
|
ty := fn.Type()
|
||||||
|
if ty.Kind() != reflect.Func {
|
||||||
|
panic("purego: fptr must be a function pointer")
|
||||||
|
}
|
||||||
|
if ty.NumOut() > 1 {
|
||||||
|
panic("purego: function can only return zero or one values")
|
||||||
|
}
|
||||||
|
if cfn == 0 {
|
||||||
|
panic("purego: cfn is nil")
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// this code checks how many registers and stack this function will use
|
||||||
|
// to avoid crashing with too many arguments
|
||||||
|
var ints int
|
||||||
|
var floats int
|
||||||
|
var stack int
|
||||||
|
for i := 0; i < ty.NumIn(); i++ {
|
||||||
|
arg := ty.In(i)
|
||||||
|
switch arg.Kind() {
|
||||||
|
case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, reflect.Slice,
|
||||||
|
reflect.Func, reflect.Bool:
|
||||||
|
if ints < numOfIntegerRegisters() {
|
||||||
|
ints++
|
||||||
|
} else {
|
||||||
|
stack++
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
if is32bit {
|
||||||
|
panic("purego: floats only supported on 64bit platforms")
|
||||||
|
}
|
||||||
|
if floats < numOfFloats {
|
||||||
|
floats++
|
||||||
|
} else {
|
||||||
|
stack++
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
if runtime.GOOS != "darwin" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64") {
|
||||||
|
panic("purego: struct arguments are only supported on darwin amd64 & arm64")
|
||||||
|
}
|
||||||
|
if arg.Size() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addInt := func(u uintptr) {
|
||||||
|
ints++
|
||||||
|
}
|
||||||
|
addFloat := func(u uintptr) {
|
||||||
|
floats++
|
||||||
|
}
|
||||||
|
addStack := func(u uintptr) {
|
||||||
|
stack++
|
||||||
|
}
|
||||||
|
_ = addStruct(reflect.New(arg).Elem(), &ints, &floats, &stack, addInt, addFloat, addStack, nil)
|
||||||
|
default:
|
||||||
|
panic("purego: unsupported kind " + arg.Kind().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
|
||||||
|
if runtime.GOOS != "darwin" {
|
||||||
|
panic("purego: struct return values only supported on darwin arm64 & amd64")
|
||||||
|
}
|
||||||
|
outType := ty.Out(0)
|
||||||
|
checkStructFieldsSupported(outType)
|
||||||
|
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
|
||||||
|
// on amd64 if struct is bigger than 16 bytes allocate the return struct
|
||||||
|
// and pass it in as a hidden first argument.
|
||||||
|
ints++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sizeOfStack := maxArgs - numOfIntegerRegisters()
|
||||||
|
if stack > sizeOfStack {
|
||||||
|
panic("purego: too many arguments")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
if variadic, ok := args[len(args)-1].Interface().([]interface{}); ok {
|
||||||
|
// subtract one from args bc the last argument in args is []interface{}
|
||||||
|
// which we are currently expanding
|
||||||
|
tmp := make([]reflect.Value, len(args)-1+len(variadic))
|
||||||
|
n := copy(tmp, args[:len(args)-1])
|
||||||
|
for i, v := range variadic {
|
||||||
|
tmp[n+i] = reflect.ValueOf(v)
|
||||||
|
}
|
||||||
|
args = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sysargs [maxArgs]uintptr
|
||||||
|
stack := sysargs[numOfIntegerRegisters():]
|
||||||
|
var floats [numOfFloats]uintptr
|
||||||
|
var numInts int
|
||||||
|
var numFloats int
|
||||||
|
var numStack int
|
||||||
|
var addStack, addInt, addFloat func(x uintptr)
|
||||||
|
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
|
||||||
|
// Windows arm64 uses the same calling convention as macOS and Linux
|
||||||
|
addStack = func(x uintptr) {
|
||||||
|
stack[numStack] = x
|
||||||
|
numStack++
|
||||||
|
}
|
||||||
|
addInt = func(x uintptr) {
|
||||||
|
if numInts >= numOfIntegerRegisters() {
|
||||||
|
addStack(x)
|
||||||
|
} else {
|
||||||
|
sysargs[numInts] = x
|
||||||
|
numInts++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addFloat = func(x uintptr) {
|
||||||
|
if numFloats < len(floats) {
|
||||||
|
floats[numFloats] = x
|
||||||
|
numFloats++
|
||||||
|
} else {
|
||||||
|
addStack(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On Windows amd64 the arguments are passed in the numbered registered.
|
||||||
|
// So the first int is in the first integer register and the first float
|
||||||
|
// is in the second floating register if there is already a first int.
|
||||||
|
// This is in contrast to how macOS and Linux pass arguments which
|
||||||
|
// tries to use as many registers as possible in the calling convention.
|
||||||
|
addStack = func(x uintptr) {
|
||||||
|
sysargs[numStack] = x
|
||||||
|
numStack++
|
||||||
|
}
|
||||||
|
addInt = addStack
|
||||||
|
addFloat = addStack
|
||||||
|
}
|
||||||
|
|
||||||
|
var keepAlive []interface{}
|
||||||
|
defer func() {
|
||||||
|
runtime.KeepAlive(keepAlive)
|
||||||
|
runtime.KeepAlive(args)
|
||||||
|
}()
|
||||||
|
var syscall syscall15Args
|
||||||
|
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
|
||||||
|
outType := ty.Out(0)
|
||||||
|
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
|
||||||
|
val := reflect.New(outType)
|
||||||
|
keepAlive = append(keepAlive, val)
|
||||||
|
addInt(val.Pointer())
|
||||||
|
} else if runtime.GOARCH == "arm64" && outType.Size() > maxRegAllocStructSize {
|
||||||
|
if !isAllSameFloat(outType) || outType.NumField() > 4 {
|
||||||
|
val := reflect.New(outType)
|
||||||
|
keepAlive = append(keepAlive, val)
|
||||||
|
syscall.arm64_r8 = val.Pointer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range args {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
ptr := strings.CString(v.String())
|
||||||
|
keepAlive = append(keepAlive, ptr)
|
||||||
|
addInt(uintptr(unsafe.Pointer(ptr)))
|
||||||
|
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
addInt(uintptr(v.Uint()))
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
addInt(uintptr(v.Int()))
|
||||||
|
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
|
||||||
|
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
|
||||||
|
addInt(v.Pointer())
|
||||||
|
case reflect.Func:
|
||||||
|
addInt(NewCallback(v.Interface()))
|
||||||
|
case reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
addInt(1)
|
||||||
|
} else {
|
||||||
|
addInt(0)
|
||||||
|
}
|
||||||
|
case reflect.Float32:
|
||||||
|
addFloat(uintptr(math.Float32bits(float32(v.Float()))))
|
||||||
|
case reflect.Float64:
|
||||||
|
addFloat(uintptr(math.Float64bits(v.Float())))
|
||||||
|
case reflect.Struct:
|
||||||
|
keepAlive = addStruct(v, &numInts, &numFloats, &numStack, addInt, addFloat, addStack, keepAlive)
|
||||||
|
default:
|
||||||
|
panic("purego: unsupported kind: " + v.Kind().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
|
||||||
|
// Use the normal arm64 calling convention even on Windows
|
||||||
|
syscall = syscall15Args{
|
||||||
|
cfn,
|
||||||
|
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5],
|
||||||
|
sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
|
||||||
|
sysargs[12], sysargs[13], sysargs[14],
|
||||||
|
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
|
||||||
|
syscall.arm64_r8,
|
||||||
|
}
|
||||||
|
runtime_cgocall(syscall15XABI0, unsafe.Pointer(&syscall))
|
||||||
|
} else {
|
||||||
|
// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats
|
||||||
|
syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4],
|
||||||
|
sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
|
||||||
|
sysargs[12], sysargs[13], sysargs[14])
|
||||||
|
syscall.f1 = syscall.a2 // on amd64 a2 stores the float return. On 32bit platforms floats aren't support
|
||||||
|
}
|
||||||
|
if ty.NumOut() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
outType := ty.Out(0)
|
||||||
|
v := reflect.New(outType).Elem()
|
||||||
|
switch outType.Kind() {
|
||||||
|
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
v.SetUint(uint64(syscall.a1))
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
v.SetInt(int64(syscall.a1))
|
||||||
|
case reflect.Bool:
|
||||||
|
v.SetBool(byte(syscall.a1) != 0)
|
||||||
|
case reflect.UnsafePointer:
|
||||||
|
// We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
|
||||||
|
v.SetPointer(*(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1)))
|
||||||
|
case reflect.Ptr:
|
||||||
|
// It is safe to have the address of syscall.r1 not escape because it is immediately dereferenced with .Elem()
|
||||||
|
v = reflect.NewAt(outType, runtime_noescape(unsafe.Pointer(&syscall.a1))).Elem()
|
||||||
|
case reflect.Func:
|
||||||
|
// wrap this C function in a nicely typed Go function
|
||||||
|
v = reflect.New(outType)
|
||||||
|
RegisterFunc(v.Interface(), syscall.a1)
|
||||||
|
case reflect.String:
|
||||||
|
v.SetString(strings.GoString(syscall.a1))
|
||||||
|
case reflect.Float32:
|
||||||
|
// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
|
||||||
|
// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
|
||||||
|
v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1))))
|
||||||
|
case reflect.Float64:
|
||||||
|
// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
|
||||||
|
// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
|
||||||
|
v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
|
||||||
|
case reflect.Struct:
|
||||||
|
v = getStruct(outType, syscall)
|
||||||
|
default:
|
||||||
|
panic("purego: unsupported return kind: " + outType.Kind().String())
|
||||||
|
}
|
||||||
|
return []reflect.Value{v}
|
||||||
|
})
|
||||||
|
fn.Set(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers.
|
||||||
|
// if it is bigger than this than enough space must be allocated on the heap and then passed into
|
||||||
|
// the function as the first parameter on amd64 or in R8 on arm64.
|
||||||
|
const maxRegAllocStructSize = 16
|
||||||
|
|
||||||
|
func isAllSameFloat(ty reflect.Type) bool {
|
||||||
|
first := ty.Field(0).Type.Kind()
|
||||||
|
if first != reflect.Float32 && first != reflect.Float64 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := 0; i < ty.NumField(); i++ {
|
||||||
|
f := ty.Field(i)
|
||||||
|
if f.Type.Kind() != first {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStructFieldsSupported(ty reflect.Type) {
|
||||||
|
for i := 0; i < ty.NumField(); i++ {
|
||||||
|
f := ty.Field(i).Type
|
||||||
|
if f.Kind() == reflect.Array {
|
||||||
|
f = f.Elem()
|
||||||
|
} else if f.Kind() == reflect.Struct {
|
||||||
|
checkStructFieldsSupported(f)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch f.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer, reflect.Float64, reflect.Float32:
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("purego: struct field type %s is not supported", f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const is32bit = unsafe.Sizeof(uintptr(0)) == 4
|
||||||
|
|
||||||
|
func roundUpTo8(val uintptr) uintptr {
|
||||||
|
return (val + 7) &^ 7
|
||||||
|
}
|
||||||
|
|
||||||
|
func numOfIntegerRegisters() int {
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "arm64":
|
||||||
|
return 8
|
||||||
|
case "amd64":
|
||||||
|
return 6
|
||||||
|
// TODO: figure out why 386 tests are not working
|
||||||
|
/*case "386":
|
||||||
|
return 0
|
||||||
|
case "arm":
|
||||||
|
return 4*/
|
||||||
|
default:
|
||||||
|
panic("purego: unknown GOARCH (" + runtime.GOARCH + ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux || windows
|
||||||
|
|
||||||
|
package purego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname runtime_cgocall runtime.cgocall
|
||||||
|
func runtime_cgocall(fn uintptr, arg unsafe.Pointer) int32 // from runtime/sys_libc.go
|
||||||
|
|
||||||
|
//go:linkname runtime_noescape runtime.noescape
|
||||||
|
//go:noescape
|
||||||
|
func runtime_noescape(p unsafe.Pointer) unsafe.Pointer // from runtime/stubs.go
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build freebsd || linux
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -ldl
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// all that is needed is to assign each dl function because then its
|
||||||
|
// symbol will then be made available to the linker and linked to inside dlfcn.go
|
||||||
|
var (
|
||||||
|
_ = C.dlopen
|
||||||
|
_ = C.dlsym
|
||||||
|
_ = C.dlerror
|
||||||
|
_ = C.dlclose
|
||||||
|
)
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
// Empty so that importing this package doesn't cause issue for certain platforms.
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build freebsd || (linux && !(arm64 || amd64))
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
// this file is placed inside internal/cgo and not package purego
|
||||||
|
// because Cgo and assembly files can't be in the same package.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -ldl
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
typedef struct syscall15Args {
|
||||||
|
uintptr_t fn;
|
||||||
|
uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15;
|
||||||
|
uintptr_t f1, f2, f3, f4, f5, f6, f7, f8;
|
||||||
|
uintptr_t r1, r2, err;
|
||||||
|
} syscall15Args;
|
||||||
|
|
||||||
|
void syscall15(struct syscall15Args *args) {
|
||||||
|
assert((args->f1|args->f2|args->f3|args->f4|args->f5|args->f6|args->f7|args->f8) == 0);
|
||||||
|
uintptr_t (*func_name)(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6,
|
||||||
|
uintptr_t a7, uintptr_t a8, uintptr_t a9, uintptr_t a10, uintptr_t a11, uintptr_t a12,
|
||||||
|
uintptr_t a13, uintptr_t a14, uintptr_t a15);
|
||||||
|
*(void**)(&func_name) = (void*)(args->fn);
|
||||||
|
uintptr_t r1 = func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9,
|
||||||
|
args->a10,args->a11,args->a12,args->a13,args->a14,args->a15);
|
||||||
|
args->r1 = r1;
|
||||||
|
args->err = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// assign purego.syscall15XABI0 to the C version of this function.
|
||||||
|
var Syscall15XABI0 = unsafe.Pointer(C.syscall15)
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
|
||||||
|
args := C.syscall15Args{
|
||||||
|
C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3),
|
||||||
|
C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6),
|
||||||
|
C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), C.uintptr_t(a10), C.uintptr_t(a11), C.uintptr_t(a12),
|
||||||
|
C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
}
|
||||||
|
C.syscall15(&args)
|
||||||
|
return uintptr(args.r1), uintptr(args.r2), uintptr(args.err)
|
||||||
|
}
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
// Macros for transitioning from the host ABI to Go ABI0.
|
||||||
|
//
|
||||||
|
// These save the frame pointer, so in general, functions that use
|
||||||
|
// these should have zero frame size to suppress the automatic frame
|
||||||
|
// pointer, though it's harmless to not do this.
|
||||||
|
|
||||||
|
#ifdef GOOS_windows
|
||||||
|
|
||||||
|
// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
|
||||||
|
// PUSH_REGS_HOST_TO_ABI0.
|
||||||
|
#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
|
||||||
|
|
||||||
|
// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
|
||||||
|
// the host ABI to Go ABI0 code. It saves all registers that are
|
||||||
|
// callee-save in the host ABI and caller-save in Go ABI0 and prepares
|
||||||
|
// for entry to Go.
|
||||||
|
//
|
||||||
|
// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
|
||||||
|
// Clear the DF flag for the Go ABI.
|
||||||
|
// MXCSR matches the Go ABI, so we don't have to set that,
|
||||||
|
// and Go doesn't modify it, so we don't have to save it.
|
||||||
|
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||||
|
PUSHFQ \
|
||||||
|
CLD \
|
||||||
|
ADJSP $(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||||
|
MOVQ DI, (0*0)(SP) \
|
||||||
|
MOVQ SI, (1*8)(SP) \
|
||||||
|
MOVQ BP, (2*8)(SP) \
|
||||||
|
MOVQ BX, (3*8)(SP) \
|
||||||
|
MOVQ R12, (4*8)(SP) \
|
||||||
|
MOVQ R13, (5*8)(SP) \
|
||||||
|
MOVQ R14, (6*8)(SP) \
|
||||||
|
MOVQ R15, (7*8)(SP) \
|
||||||
|
MOVUPS X6, (8*8)(SP) \
|
||||||
|
MOVUPS X7, (10*8)(SP) \
|
||||||
|
MOVUPS X8, (12*8)(SP) \
|
||||||
|
MOVUPS X9, (14*8)(SP) \
|
||||||
|
MOVUPS X10, (16*8)(SP) \
|
||||||
|
MOVUPS X11, (18*8)(SP) \
|
||||||
|
MOVUPS X12, (20*8)(SP) \
|
||||||
|
MOVUPS X13, (22*8)(SP) \
|
||||||
|
MOVUPS X14, (24*8)(SP) \
|
||||||
|
MOVUPS X15, (26*8)(SP)
|
||||||
|
|
||||||
|
#define POP_REGS_HOST_TO_ABI0() \
|
||||||
|
MOVQ (0*0)(SP), DI \
|
||||||
|
MOVQ (1*8)(SP), SI \
|
||||||
|
MOVQ (2*8)(SP), BP \
|
||||||
|
MOVQ (3*8)(SP), BX \
|
||||||
|
MOVQ (4*8)(SP), R12 \
|
||||||
|
MOVQ (5*8)(SP), R13 \
|
||||||
|
MOVQ (6*8)(SP), R14 \
|
||||||
|
MOVQ (7*8)(SP), R15 \
|
||||||
|
MOVUPS (8*8)(SP), X6 \
|
||||||
|
MOVUPS (10*8)(SP), X7 \
|
||||||
|
MOVUPS (12*8)(SP), X8 \
|
||||||
|
MOVUPS (14*8)(SP), X9 \
|
||||||
|
MOVUPS (16*8)(SP), X10 \
|
||||||
|
MOVUPS (18*8)(SP), X11 \
|
||||||
|
MOVUPS (20*8)(SP), X12 \
|
||||||
|
MOVUPS (22*8)(SP), X13 \
|
||||||
|
MOVUPS (24*8)(SP), X14 \
|
||||||
|
MOVUPS (26*8)(SP), X15 \
|
||||||
|
ADJSP $-(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||||
|
POPFQ
|
||||||
|
|
||||||
|
#else
|
||||||
|
// SysV ABI
|
||||||
|
|
||||||
|
#define REGS_HOST_TO_ABI0_STACK (6*8)
|
||||||
|
|
||||||
|
// SysV MXCSR matches the Go ABI, so we don't have to set that,
|
||||||
|
// and Go doesn't modify it, so we don't have to save it.
|
||||||
|
// Both SysV and Go require DF to be cleared, so that's already clear.
|
||||||
|
// The SysV and Go frame pointer conventions are compatible.
|
||||||
|
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||||
|
ADJSP $(REGS_HOST_TO_ABI0_STACK) \
|
||||||
|
MOVQ BP, (5*8)(SP) \
|
||||||
|
LEAQ (5*8)(SP), BP \
|
||||||
|
MOVQ BX, (0*8)(SP) \
|
||||||
|
MOVQ R12, (1*8)(SP) \
|
||||||
|
MOVQ R13, (2*8)(SP) \
|
||||||
|
MOVQ R14, (3*8)(SP) \
|
||||||
|
MOVQ R15, (4*8)(SP)
|
||||||
|
|
||||||
|
#define POP_REGS_HOST_TO_ABI0() \
|
||||||
|
MOVQ (0*8)(SP), BX \
|
||||||
|
MOVQ (1*8)(SP), R12 \
|
||||||
|
MOVQ (2*8)(SP), R13 \
|
||||||
|
MOVQ (3*8)(SP), R14 \
|
||||||
|
MOVQ (4*8)(SP), R15 \
|
||||||
|
MOVQ (5*8)(SP), BP \
|
||||||
|
ADJSP $-(REGS_HOST_TO_ABI0_STACK)
|
||||||
|
|
||||||
|
#endif
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
// Macros for transitioning from the host ABI to Go ABI0.
|
||||||
|
//
|
||||||
|
// These macros save and restore the callee-saved registers
|
||||||
|
// from the stack, but they don't adjust stack pointer, so
|
||||||
|
// the user should prepare stack space in advance.
|
||||||
|
// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
|
||||||
|
// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
|
||||||
|
//
|
||||||
|
// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
|
||||||
|
// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
|
||||||
|
//
|
||||||
|
// R29 is not saved because Go will save and restore it.
|
||||||
|
|
||||||
|
#define SAVE_R19_TO_R28(offset) \
|
||||||
|
STP (R19, R20), ((offset)+0*8)(RSP) \
|
||||||
|
STP (R21, R22), ((offset)+2*8)(RSP) \
|
||||||
|
STP (R23, R24), ((offset)+4*8)(RSP) \
|
||||||
|
STP (R25, R26), ((offset)+6*8)(RSP) \
|
||||||
|
STP (R27, g), ((offset)+8*8)(RSP)
|
||||||
|
#define RESTORE_R19_TO_R28(offset) \
|
||||||
|
LDP ((offset)+0*8)(RSP), (R19, R20) \
|
||||||
|
LDP ((offset)+2*8)(RSP), (R21, R22) \
|
||||||
|
LDP ((offset)+4*8)(RSP), (R23, R24) \
|
||||||
|
LDP ((offset)+6*8)(RSP), (R25, R26) \
|
||||||
|
LDP ((offset)+8*8)(RSP), (R27, g) /* R28 */
|
||||||
|
#define SAVE_F8_TO_F15(offset) \
|
||||||
|
FSTPD (F8, F9), ((offset)+0*8)(RSP) \
|
||||||
|
FSTPD (F10, F11), ((offset)+2*8)(RSP) \
|
||||||
|
FSTPD (F12, F13), ((offset)+4*8)(RSP) \
|
||||||
|
FSTPD (F14, F15), ((offset)+6*8)(RSP)
|
||||||
|
#define RESTORE_F8_TO_F15(offset) \
|
||||||
|
FLDPD ((offset)+0*8)(RSP), (F8, F9) \
|
||||||
|
FLDPD ((offset)+2*8)(RSP), (F10, F11) \
|
||||||
|
FLDPD ((offset)+4*8)(RSP), (F12, F13) \
|
||||||
|
FLDPD ((offset)+6*8)(RSP), (F14, F15)
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2009 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 "textflag.h"
|
||||||
|
#include "abi_amd64.h"
|
||||||
|
|
||||||
|
// Called by C code generated by cmd/cgo.
|
||||||
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
// fn is the PC of a func(a unsafe.Pointer) function.
|
||||||
|
// This signature is known to SWIG, so we can't change it.
|
||||||
|
TEXT crosscall2(SB), NOSPLIT, $0-0
|
||||||
|
PUSH_REGS_HOST_TO_ABI0()
|
||||||
|
|
||||||
|
// Make room for arguments to cgocallback.
|
||||||
|
ADJSP $0x18
|
||||||
|
|
||||||
|
#ifndef GOOS_windows
|
||||||
|
MOVQ DI, 0x0(SP) // fn
|
||||||
|
MOVQ SI, 0x8(SP) // arg
|
||||||
|
|
||||||
|
// Skip n in DX.
|
||||||
|
MOVQ CX, 0x10(SP) // ctxt
|
||||||
|
|
||||||
|
#else
|
||||||
|
MOVQ CX, 0x0(SP) // fn
|
||||||
|
MOVQ DX, 0x8(SP) // arg
|
||||||
|
|
||||||
|
// Skip n in R8.
|
||||||
|
MOVQ R9, 0x10(SP) // ctxt
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CALL runtime·cgocallback(SB)
|
||||||
|
|
||||||
|
ADJSP $-0x18
|
||||||
|
POP_REGS_HOST_TO_ABI0()
|
||||||
|
RET
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// 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 "textflag.h"
|
||||||
|
#include "abi_arm64.h"
|
||||||
|
|
||||||
|
// Called by C code generated by cmd/cgo.
|
||||||
|
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
|
// Saves C callee-saved registers and calls cgocallback with three arguments.
|
||||||
|
// fn is the PC of a func(a unsafe.Pointer) function.
|
||||||
|
TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
|
||||||
|
/*
|
||||||
|
* We still need to save all callee save register as before, and then
|
||||||
|
* push 3 args for fn (R0, R1, R3), skipping R2.
|
||||||
|
* Also note that at procedure entry in gc world, 8(RSP) will be the
|
||||||
|
* first arg.
|
||||||
|
*/
|
||||||
|
SUB $(8*24), RSP
|
||||||
|
STP (R0, R1), (8*1)(RSP)
|
||||||
|
MOVD R3, (8*3)(RSP)
|
||||||
|
|
||||||
|
SAVE_R19_TO_R28(8*4)
|
||||||
|
SAVE_F8_TO_F15(8*14)
|
||||||
|
STP (R29, R30), (8*22)(RSP)
|
||||||
|
|
||||||
|
// Initialize Go ABI environment
|
||||||
|
BL runtime·load_g(SB)
|
||||||
|
BL runtime·cgocallback(SB)
|
||||||
|
|
||||||
|
RESTORE_R19_TO_R28(8*4)
|
||||||
|
RESTORE_F8_TO_F15(8*14)
|
||||||
|
LDP (8*22)(RSP), (R29, R30)
|
||||||
|
|
||||||
|
ADD $(8*24), RSP
|
||||||
|
RET
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: decide if we need _runtime_cgo_panic_internal
|
||||||
|
|
||||||
|
//go:linkname x_cgo_init_trampoline x_cgo_init_trampoline
|
||||||
|
//go:linkname _cgo_init _cgo_init
|
||||||
|
var x_cgo_init_trampoline byte
|
||||||
|
var _cgo_init = &x_cgo_init_trampoline
|
||||||
|
|
||||||
|
// Creates a new system thread without updating any Go state.
|
||||||
|
//
|
||||||
|
// This method is invoked during shared library loading to create a new OS
|
||||||
|
// thread to perform the runtime initialization. This method is similar to
|
||||||
|
// _cgo_sys_thread_start except that it doesn't update any Go state.
|
||||||
|
|
||||||
|
//go:linkname x_cgo_thread_start_trampoline x_cgo_thread_start_trampoline
|
||||||
|
//go:linkname _cgo_thread_start _cgo_thread_start
|
||||||
|
var x_cgo_thread_start_trampoline byte
|
||||||
|
var _cgo_thread_start = &x_cgo_thread_start_trampoline
|
||||||
|
|
||||||
|
// Notifies that the runtime has been initialized.
|
||||||
|
//
|
||||||
|
// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
|
||||||
|
// to ensure that the runtime has been initialized before the CGO call is
|
||||||
|
// executed. This is necessary for shared libraries where we kickoff runtime
|
||||||
|
// initialization in a separate thread and return without waiting for this
|
||||||
|
// thread to complete the init.
|
||||||
|
|
||||||
|
//go:linkname x_cgo_notify_runtime_init_done_trampoline x_cgo_notify_runtime_init_done_trampoline
|
||||||
|
//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
|
||||||
|
var x_cgo_notify_runtime_init_done_trampoline byte
|
||||||
|
var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done_trampoline
|
||||||
|
|
||||||
|
// Indicates whether a dummy thread key has been created or not.
|
||||||
|
//
|
||||||
|
// When calling go exported function from C, we register a destructor
|
||||||
|
// callback, for a dummy thread key, by using pthread_key_create.
|
||||||
|
|
||||||
|
//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created
|
||||||
|
var x_cgo_pthread_key_created uintptr
|
||||||
|
var _cgo_pthread_key_created = &x_cgo_pthread_key_created
|
||||||
|
|
||||||
|
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
|
||||||
|
// It's for the runtime package to call at init time.
|
||||||
|
func set_crosscall2() {
|
||||||
|
// nothing needs to be done here for fakecgo
|
||||||
|
// because it's possible to just call cgocallback directly
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname _set_crosscall2 runtime.set_crosscall2
|
||||||
|
var _set_crosscall2 = set_crosscall2
|
||||||
|
|
||||||
|
// Store the g into the thread-specific value.
|
||||||
|
// So that pthread_key_destructor will dropm when the thread is exiting.
|
||||||
|
|
||||||
|
//go:linkname x_cgo_bindm_trampoline x_cgo_bindm_trampoline
|
||||||
|
//go:linkname _cgo_bindm _cgo_bindm
|
||||||
|
var x_cgo_bindm_trampoline byte
|
||||||
|
var _cgo_bindm = &x_cgo_bindm_trampoline
|
||||||
|
|
||||||
|
// TODO: decide if we need x_cgo_set_context_function
|
||||||
|
// TODO: decide if we need _cgo_yield
|
||||||
|
|
||||||
|
var (
|
||||||
|
// In Go 1.20 the race detector was rewritten to pure Go
|
||||||
|
// on darwin. This means that when CGO_ENABLED=0 is set
|
||||||
|
// fakecgo is built with race detector code. This is not
|
||||||
|
// good since this code is pretending to be C. The go:norace
|
||||||
|
// pragma is not enough, since it only applies to the native
|
||||||
|
// ABIInternal function. The ABIO wrapper (which is necessary,
|
||||||
|
// since all references to text symbols from assembly will use it)
|
||||||
|
// does not inherit the go:norace pragma, so it will still be
|
||||||
|
// instrumented by the race detector.
|
||||||
|
//
|
||||||
|
// To circumvent this issue, using closure calls in the
|
||||||
|
// assembly, which forces the compiler to use the ABIInternal
|
||||||
|
// native implementation (which has go:norace) instead.
|
||||||
|
threadentry_call = threadentry
|
||||||
|
x_cgo_init_call = x_cgo_init
|
||||||
|
x_cgo_setenv_call = x_cgo_setenv
|
||||||
|
x_cgo_unsetenv_call = x_cgo_unsetenv
|
||||||
|
x_cgo_thread_start_call = x_cgo_thread_start
|
||||||
|
)
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd
|
||||||
|
|
||||||
|
// Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go.
|
||||||
|
// This allows code that calls into C to function properly when CGO_ENABLED=0.
|
||||||
|
//
|
||||||
|
// # Goals
|
||||||
|
//
|
||||||
|
// fakecgo attempts to replicate the same naming structure as in the runtime.
|
||||||
|
// For example, functions that have the prefix "gcc_*" are named "go_*".
|
||||||
|
// This makes it easier to port other GOOSs and GOARCHs as well as to keep
|
||||||
|
// it in sync with runtime/cgo.
|
||||||
|
//
|
||||||
|
// # Support
|
||||||
|
//
|
||||||
|
// Currently, fakecgo only supports macOS on amd64 & arm64. It also cannot
|
||||||
|
// be used with -buildmode=c-archive because that requires special initialization
|
||||||
|
// that fakecgo does not implement at the moment.
|
||||||
|
//
|
||||||
|
// # Usage
|
||||||
|
//
|
||||||
|
// Using fakecgo is easy just import _ "github.com/ebitengine/purego" and then
|
||||||
|
// set the environment variable CGO_ENABLED=0.
|
||||||
|
// The recommended usage for fakecgo is to prefer using runtime/cgo if possible
|
||||||
|
// but if cross-compiling or fast build times are important fakecgo is available.
|
||||||
|
// Purego will pick which ever Cgo runtime is available and prefer the one that
|
||||||
|
// comes with Go (runtime/cgo).
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
//go:generate go run gen.go
|
||||||
|
//go:generate gofmt -s -w symbols.go
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2010 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.
|
||||||
|
|
||||||
|
//go:build freebsd && !cgo
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import _ "unsafe" // for go:linkname
|
||||||
|
|
||||||
|
// Supply environ and __progname, because we don't
|
||||||
|
// link against the standard FreeBSD crt0.o and the
|
||||||
|
// libc dynamic library needs them.
|
||||||
|
|
||||||
|
// Note: when building with cross-compiling or CGO_ENABLED=0, add
|
||||||
|
// the following argument to `go` so that these symbols are defined by
|
||||||
|
// making fakecgo the Cgo.
|
||||||
|
// -gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"
|
||||||
|
|
||||||
|
//go:linkname _environ environ
|
||||||
|
//go:linkname _progname __progname
|
||||||
|
|
||||||
|
//go:cgo_export_dynamic environ
|
||||||
|
//go:cgo_export_dynamic __progname
|
||||||
|
|
||||||
|
var _environ uintptr
|
||||||
|
var _progname uintptr
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
size = pthread_get_stacksize_np(pthread_self())
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_setstacksize(&attr, size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
|
||||||
|
size = pthread_get_stacksize_np(pthread_self())
|
||||||
|
g.stacklo = uintptr(unsafe.Add(unsafe.Pointer(&size), -size+4096))
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
size = pthread_get_stacksize_np(pthread_self())
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_setstacksize(&attr, size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
// TODO: support ios
|
||||||
|
//#if TARGET_OS_IPHONE
|
||||||
|
// darwin_arm_init_thread_exception_port();
|
||||||
|
//#endif
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
|
||||||
|
// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
|
||||||
|
// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
|
||||||
|
// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
size = pthread_get_stacksize_np(pthread_self())
|
||||||
|
g.stacklo = uintptr(unsafe.Add(unsafe.Pointer(&size), -size+4096))
|
||||||
|
|
||||||
|
//TODO: support ios
|
||||||
|
//#if TARGET_OS_IPHONE
|
||||||
|
// darwin_arm_init_mach_exception_handler();
|
||||||
|
// darwin_arm_init_thread_exception_port();
|
||||||
|
// init_working_dir();
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_getstacksize(&attr, &size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
var attr *pthread_attr_t
|
||||||
|
|
||||||
|
/* The memory sanitizer distributed with versions of clang
|
||||||
|
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||||
|
may return an address that is later overwritten by the msan
|
||||||
|
library. Avoid this problem by forcing a call to malloc
|
||||||
|
here, before we ever call malloc.
|
||||||
|
|
||||||
|
This is only required for the memory sanitizer, so it's
|
||||||
|
unfortunate that we always run it. It should be possible
|
||||||
|
to remove this when we no longer care about versions of
|
||||||
|
clang before 3.8. The test for this is
|
||||||
|
misc/cgo/testsanitizers.
|
||||||
|
|
||||||
|
GCC works hard to eliminate a seemingly unnecessary call to
|
||||||
|
malloc, so we actually use the memory we allocate. */
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
|
||||||
|
if attr == nil {
|
||||||
|
println("fakecgo: malloc failed")
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
pthread_attr_init(attr)
|
||||||
|
pthread_attr_getstacksize(attr, &size)
|
||||||
|
// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
|
||||||
|
// but this should be OK since we are taking the address of the first variable in this function.
|
||||||
|
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
|
||||||
|
pthread_attr_destroy(attr)
|
||||||
|
free(unsafe.Pointer(attr))
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_getstacksize(&attr, &size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
|
||||||
|
// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
|
||||||
|
// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
|
||||||
|
// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
var attr *pthread_attr_t
|
||||||
|
|
||||||
|
/* The memory sanitizer distributed with versions of clang
|
||||||
|
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||||
|
may return an address that is later overwritten by the msan
|
||||||
|
library. Avoid this problem by forcing a call to malloc
|
||||||
|
here, before we ever call malloc.
|
||||||
|
|
||||||
|
This is only required for the memory sanitizer, so it's
|
||||||
|
unfortunate that we always run it. It should be possible
|
||||||
|
to remove this when we no longer care about versions of
|
||||||
|
clang before 3.8. The test for this is
|
||||||
|
misc/cgo/testsanitizers.
|
||||||
|
|
||||||
|
GCC works hard to eliminate a seemingly unnecessary call to
|
||||||
|
malloc, so we actually use the memory we allocate. */
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
|
||||||
|
if attr == nil {
|
||||||
|
println("fakecgo: malloc failed")
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
pthread_attr_init(attr)
|
||||||
|
pthread_attr_getstacksize(attr, &size)
|
||||||
|
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
|
||||||
|
pthread_attr_destroy(attr)
|
||||||
|
free(unsafe.Pointer(attr))
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pthread_g pthread_key_t
|
||||||
|
|
||||||
|
runtime_init_cond = PTHREAD_COND_INITIALIZER
|
||||||
|
runtime_init_mu = PTHREAD_MUTEX_INITIALIZER
|
||||||
|
runtime_init_done int
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func x_cgo_notify_runtime_init_done() {
|
||||||
|
pthread_mutex_lock(&runtime_init_mu)
|
||||||
|
runtime_init_done = 1
|
||||||
|
pthread_cond_broadcast(&runtime_init_cond)
|
||||||
|
pthread_mutex_unlock(&runtime_init_mu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the g into a thread-specific value associated with the pthread key pthread_g.
|
||||||
|
// And pthread_key_destructor will dropm when the thread is exiting.
|
||||||
|
func x_cgo_bindm(g unsafe.Pointer) {
|
||||||
|
// We assume this will always succeed, otherwise, there might be extra M leaking,
|
||||||
|
// when a C thread exits after a cgo call.
|
||||||
|
// We only invoke this function once per thread in runtime.needAndBindM,
|
||||||
|
// and the next calls just reuse the bound m.
|
||||||
|
pthread_setspecific(pthread_g, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _cgo_try_pthread_create retries pthread_create if it fails with
|
||||||
|
// EAGAIN.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func _cgo_try_pthread_create(thread *pthread_t, attr *pthread_attr_t, pfn unsafe.Pointer, arg *ThreadStart) int {
|
||||||
|
var ts syscall.Timespec
|
||||||
|
// tries needs to be the same type as syscall.Timespec.Nsec
|
||||||
|
// but the fields are int32 on 32bit and int64 on 64bit.
|
||||||
|
// tries is assigned to syscall.Timespec.Nsec in order to match its type.
|
||||||
|
tries := ts.Nsec
|
||||||
|
var err int
|
||||||
|
|
||||||
|
for tries = 0; tries < 20; tries++ {
|
||||||
|
err = int(pthread_create(thread, attr, pfn, unsafe.Pointer(arg)))
|
||||||
|
if err == 0 {
|
||||||
|
pthread_detach(*thread)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if err != int(syscall.EAGAIN) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ts.Sec = 0
|
||||||
|
ts.Nsec = (tries + 1) * 1000 * 1000 // Milliseconds.
|
||||||
|
nanosleep(&ts, nil)
|
||||||
|
}
|
||||||
|
return int(syscall.EAGAIN)
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_getstacksize(&attr, &size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
var attr *pthread_attr_t
|
||||||
|
|
||||||
|
/* The memory sanitizer distributed with versions of clang
|
||||||
|
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||||
|
may return an address that is later overwritten by the msan
|
||||||
|
library. Avoid this problem by forcing a call to malloc
|
||||||
|
here, before we ever call malloc.
|
||||||
|
|
||||||
|
This is only required for the memory sanitizer, so it's
|
||||||
|
unfortunate that we always run it. It should be possible
|
||||||
|
to remove this when we no longer care about versions of
|
||||||
|
clang before 3.8. The test for this is
|
||||||
|
misc/cgo/testsanitizers.
|
||||||
|
|
||||||
|
GCC works hard to eliminate a seemingly unnecessary call to
|
||||||
|
malloc, so we actually use the memory we allocate. */
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
|
||||||
|
if attr == nil {
|
||||||
|
println("fakecgo: malloc failed")
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
pthread_attr_init(attr)
|
||||||
|
pthread_attr_getstacksize(attr, &size)
|
||||||
|
// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
|
||||||
|
// but this should be OK since we are taking the address of the first variable in this function.
|
||||||
|
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
|
||||||
|
pthread_attr_destroy(attr)
|
||||||
|
free(unsafe.Pointer(attr))
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2011 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 fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func _cgo_sys_thread_start(ts *ThreadStart) {
|
||||||
|
var attr pthread_attr_t
|
||||||
|
var ign, oset sigset_t
|
||||||
|
var p pthread_t
|
||||||
|
var size size_t
|
||||||
|
var err int
|
||||||
|
|
||||||
|
//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
|
||||||
|
sigfillset(&ign)
|
||||||
|
pthread_sigmask(SIG_SETMASK, &ign, &oset)
|
||||||
|
|
||||||
|
pthread_attr_init(&attr)
|
||||||
|
pthread_attr_getstacksize(&attr, &size)
|
||||||
|
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
|
||||||
|
ts.g.stackhi = uintptr(size)
|
||||||
|
|
||||||
|
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
|
||||||
|
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oset, nil)
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
print("fakecgo: pthread_create failed: ")
|
||||||
|
println(err)
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
|
||||||
|
//
|
||||||
|
//go:linkname x_threadentry_trampoline threadentry_trampoline
|
||||||
|
var x_threadentry_trampoline byte
|
||||||
|
var threadentry_trampolineABI0 = &x_threadentry_trampoline
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
func threadentry(v unsafe.Pointer) unsafe.Pointer {
|
||||||
|
ts := *(*ThreadStart)(v)
|
||||||
|
free(v)
|
||||||
|
|
||||||
|
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
|
||||||
|
|
||||||
|
// faking funcs in go is a bit a... involved - but the following works :)
|
||||||
|
fn := uintptr(unsafe.Pointer(&ts.fn))
|
||||||
|
(*(*func())(unsafe.Pointer(&fn)))()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we will store a pointer to the provided setg func
|
||||||
|
var setg_func uintptr
|
||||||
|
|
||||||
|
// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
|
||||||
|
// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
|
||||||
|
// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
|
||||||
|
// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
func x_cgo_init(g *G, setg uintptr) {
|
||||||
|
var size size_t
|
||||||
|
var attr *pthread_attr_t
|
||||||
|
|
||||||
|
/* The memory sanitizer distributed with versions of clang
|
||||||
|
before 3.8 has a bug: if you call mmap before malloc, mmap
|
||||||
|
may return an address that is later overwritten by the msan
|
||||||
|
library. Avoid this problem by forcing a call to malloc
|
||||||
|
here, before we ever call malloc.
|
||||||
|
|
||||||
|
This is only required for the memory sanitizer, so it's
|
||||||
|
unfortunate that we always run it. It should be possible
|
||||||
|
to remove this when we no longer care about versions of
|
||||||
|
clang before 3.8. The test for this is
|
||||||
|
misc/cgo/testsanitizers.
|
||||||
|
|
||||||
|
GCC works hard to eliminate a seemingly unnecessary call to
|
||||||
|
malloc, so we actually use the memory we allocate. */
|
||||||
|
|
||||||
|
setg_func = setg
|
||||||
|
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
|
||||||
|
if attr == nil {
|
||||||
|
println("fakecgo: malloc failed")
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
pthread_attr_init(attr)
|
||||||
|
pthread_attr_getstacksize(attr, &size)
|
||||||
|
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
|
||||||
|
pthread_attr_destroy(attr)
|
||||||
|
free(unsafe.Pointer(attr))
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func x_cgo_setenv(arg *[2]*byte) {
|
||||||
|
setenv(arg[0], arg[1], 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func x_cgo_unsetenv(arg *[1]*byte) {
|
||||||
|
unsetenv(arg[0])
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// _cgo_thread_start is split into three parts in cgo since only one part is system dependent (keep it here for easier handling)
|
||||||
|
|
||||||
|
// _cgo_thread_start(ThreadStart *arg) (runtime/cgo/gcc_util.c)
|
||||||
|
// This get's called instead of the go code for creating new threads
|
||||||
|
// -> pthread_* stuff is used, so threads are setup correctly for C
|
||||||
|
// If this is missing, TLS is only setup correctly on thread 1!
|
||||||
|
// This function should be go:systemstack instead of go:nosplit (but that requires runtime)
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
//go:norace
|
||||||
|
func x_cgo_thread_start(arg *ThreadStart) {
|
||||||
|
var ts *ThreadStart
|
||||||
|
// Make our own copy that can persist after we return.
|
||||||
|
// _cgo_tsan_acquire();
|
||||||
|
ts = (*ThreadStart)(malloc(unsafe.Sizeof(*ts)))
|
||||||
|
// _cgo_tsan_release();
|
||||||
|
if ts == nil {
|
||||||
|
println("fakecgo: out of memory in thread_start")
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
// *ts = *arg would cause a writebarrier so use memmove instead
|
||||||
|
memmove(unsafe.Pointer(ts), unsafe.Pointer(arg), unsafe.Sizeof(*ts))
|
||||||
|
_cgo_sys_thread_start(ts) // OS-dependent half
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2010 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.
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
// The runtime package contains an uninitialized definition
|
||||||
|
// for runtime·iscgo. Override it to tell the runtime we're here.
|
||||||
|
// There are various function pointers that should be set too,
|
||||||
|
// but those depend on dynamic linker magic to get initialized
|
||||||
|
// correctly, and sometimes they break. This variable is a
|
||||||
|
// backup: it depends only on old C style static linking rules.
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import _ "unsafe" // for go:linkname
|
||||||
|
|
||||||
|
//go:linkname _iscgo runtime.iscgo
|
||||||
|
var _iscgo bool = true
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
type (
|
||||||
|
size_t uintptr
|
||||||
|
sigset_t [128]byte
|
||||||
|
pthread_attr_t [64]byte
|
||||||
|
pthread_t int
|
||||||
|
pthread_key_t uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
// for pthread_sigmask:
|
||||||
|
|
||||||
|
type sighow int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SIG_BLOCK sighow = 0
|
||||||
|
SIG_UNBLOCK sighow = 1
|
||||||
|
SIG_SETMASK sighow = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type G struct {
|
||||||
|
stacklo uintptr
|
||||||
|
stackhi uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadStart struct {
|
||||||
|
g *G
|
||||||
|
tls *uintptr
|
||||||
|
fn uintptr
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
type (
|
||||||
|
pthread_mutex_t struct {
|
||||||
|
sig int64
|
||||||
|
opaque [56]byte
|
||||||
|
}
|
||||||
|
pthread_cond_t struct {
|
||||||
|
sig int64
|
||||||
|
opaque [40]byte
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB}
|
||||||
|
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7}
|
||||||
|
)
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
type (
|
||||||
|
pthread_cond_t uintptr
|
||||||
|
pthread_mutex_t uintptr
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
|
||||||
|
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
|
||||||
|
)
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
type (
|
||||||
|
pthread_cond_t [48]byte
|
||||||
|
pthread_mutex_t [48]byte
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PTHREAD_COND_INITIALIZER = pthread_cond_t{}
|
||||||
|
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{}
|
||||||
|
)
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import _ "unsafe" // for go:linkname
|
||||||
|
|
||||||
|
//go:linkname x_cgo_setenv_trampoline x_cgo_setenv_trampoline
|
||||||
|
//go:linkname _cgo_setenv runtime._cgo_setenv
|
||||||
|
var x_cgo_setenv_trampoline byte
|
||||||
|
var _cgo_setenv = &x_cgo_setenv_trampoline
|
||||||
|
|
||||||
|
//go:linkname x_cgo_unsetenv_trampoline x_cgo_unsetenv_trampoline
|
||||||
|
//go:linkname _cgo_unsetenv runtime._cgo_unsetenv
|
||||||
|
var x_cgo_unsetenv_trampoline byte
|
||||||
|
var _cgo_unsetenv = &x_cgo_unsetenv_trampoline
|
||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || freebsd || linux
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setg_trampoline calls setg with the G provided
|
||||||
|
func setg_trampoline(setg uintptr, G uintptr)
|
||||||
|
|
||||||
|
//go:linkname memmove runtime.memmove
|
||||||
|
func memmove(to, from unsafe.Pointer, n uintptr)
|
||||||
|
|
||||||
|
// call5 takes fn the C function and 5 arguments and calls the function with those arguments
|
||||||
|
func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
|
||||||
|
|
||||||
|
func malloc(size uintptr) unsafe.Pointer {
|
||||||
|
ret := call5(mallocABI0, uintptr(size), 0, 0, 0, 0)
|
||||||
|
// this indirection is to avoid go vet complaining about possible misuse of unsafe.Pointer
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
func free(ptr unsafe.Pointer) {
|
||||||
|
call5(freeABI0, uintptr(ptr), 0, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setenv(name *byte, value *byte, overwrite int32) int32 {
|
||||||
|
return int32(call5(setenvABI0, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(overwrite), 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func unsetenv(name *byte) int32 {
|
||||||
|
return int32(call5(unsetenvABI0, uintptr(unsafe.Pointer(name)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func sigfillset(set *sigset_t) int32 {
|
||||||
|
return int32(call5(sigfillsetABI0, uintptr(unsafe.Pointer(set)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func nanosleep(ts *syscall.Timespec, rem *syscall.Timespec) int32 {
|
||||||
|
return int32(call5(nanosleepABI0, uintptr(unsafe.Pointer(ts)), uintptr(unsafe.Pointer(rem)), 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func abort() {
|
||||||
|
call5(abortABI0, 0, 0, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_attr_init(attr *pthread_attr_t) int32 {
|
||||||
|
return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_create(thread *pthread_t, attr *pthread_attr_t, start unsafe.Pointer, arg unsafe.Pointer) int32 {
|
||||||
|
return int32(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(start), uintptr(arg), 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_detach(thread pthread_t) int32 {
|
||||||
|
return int32(call5(pthread_detachABI0, uintptr(thread), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_sigmask(how sighow, ign *sigset_t, oset *sigset_t) int32 {
|
||||||
|
return int32(call5(pthread_sigmaskABI0, uintptr(how), uintptr(unsafe.Pointer(ign)), uintptr(unsafe.Pointer(oset)), 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_self() pthread_t {
|
||||||
|
return pthread_t(call5(pthread_selfABI0, 0, 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_get_stacksize_np(thread pthread_t) size_t {
|
||||||
|
return size_t(call5(pthread_get_stacksize_npABI0, uintptr(thread), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
|
||||||
|
return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_attr_setstacksize(attr *pthread_attr_t, size size_t) int32 {
|
||||||
|
return int32(call5(pthread_attr_setstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(size), 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_attr_destroy(attr *pthread_attr_t) int32 {
|
||||||
|
return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_mutex_lock(mutex *pthread_mutex_t) int32 {
|
||||||
|
return int32(call5(pthread_mutex_lockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_mutex_unlock(mutex *pthread_mutex_t) int32 {
|
||||||
|
return int32(call5(pthread_mutex_unlockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_cond_broadcast(cond *pthread_cond_t) int32 {
|
||||||
|
return int32(call5(pthread_cond_broadcastABI0, uintptr(unsafe.Pointer(cond)), 0, 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {
|
||||||
|
return int32(call5(pthread_setspecificABI0, uintptr(key), uintptr(value), 0, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname _malloc _malloc
|
||||||
|
var _malloc uintptr
|
||||||
|
var mallocABI0 = uintptr(unsafe.Pointer(&_malloc))
|
||||||
|
|
||||||
|
//go:linkname _free _free
|
||||||
|
var _free uintptr
|
||||||
|
var freeABI0 = uintptr(unsafe.Pointer(&_free))
|
||||||
|
|
||||||
|
//go:linkname _setenv _setenv
|
||||||
|
var _setenv uintptr
|
||||||
|
var setenvABI0 = uintptr(unsafe.Pointer(&_setenv))
|
||||||
|
|
||||||
|
//go:linkname _unsetenv _unsetenv
|
||||||
|
var _unsetenv uintptr
|
||||||
|
var unsetenvABI0 = uintptr(unsafe.Pointer(&_unsetenv))
|
||||||
|
|
||||||
|
//go:linkname _sigfillset _sigfillset
|
||||||
|
var _sigfillset uintptr
|
||||||
|
var sigfillsetABI0 = uintptr(unsafe.Pointer(&_sigfillset))
|
||||||
|
|
||||||
|
//go:linkname _nanosleep _nanosleep
|
||||||
|
var _nanosleep uintptr
|
||||||
|
var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep))
|
||||||
|
|
||||||
|
//go:linkname _abort _abort
|
||||||
|
var _abort uintptr
|
||||||
|
var abortABI0 = uintptr(unsafe.Pointer(&_abort))
|
||||||
|
|
||||||
|
//go:linkname _pthread_attr_init _pthread_attr_init
|
||||||
|
var _pthread_attr_init uintptr
|
||||||
|
var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init))
|
||||||
|
|
||||||
|
//go:linkname _pthread_create _pthread_create
|
||||||
|
var _pthread_create uintptr
|
||||||
|
var pthread_createABI0 = uintptr(unsafe.Pointer(&_pthread_create))
|
||||||
|
|
||||||
|
//go:linkname _pthread_detach _pthread_detach
|
||||||
|
var _pthread_detach uintptr
|
||||||
|
var pthread_detachABI0 = uintptr(unsafe.Pointer(&_pthread_detach))
|
||||||
|
|
||||||
|
//go:linkname _pthread_sigmask _pthread_sigmask
|
||||||
|
var _pthread_sigmask uintptr
|
||||||
|
var pthread_sigmaskABI0 = uintptr(unsafe.Pointer(&_pthread_sigmask))
|
||||||
|
|
||||||
|
//go:linkname _pthread_self _pthread_self
|
||||||
|
var _pthread_self uintptr
|
||||||
|
var pthread_selfABI0 = uintptr(unsafe.Pointer(&_pthread_self))
|
||||||
|
|
||||||
|
//go:linkname _pthread_get_stacksize_np _pthread_get_stacksize_np
|
||||||
|
var _pthread_get_stacksize_np uintptr
|
||||||
|
var pthread_get_stacksize_npABI0 = uintptr(unsafe.Pointer(&_pthread_get_stacksize_np))
|
||||||
|
|
||||||
|
//go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize
|
||||||
|
var _pthread_attr_getstacksize uintptr
|
||||||
|
var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize))
|
||||||
|
|
||||||
|
//go:linkname _pthread_attr_setstacksize _pthread_attr_setstacksize
|
||||||
|
var _pthread_attr_setstacksize uintptr
|
||||||
|
var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize))
|
||||||
|
|
||||||
|
//go:linkname _pthread_attr_destroy _pthread_attr_destroy
|
||||||
|
var _pthread_attr_destroy uintptr
|
||||||
|
var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
|
||||||
|
|
||||||
|
//go:linkname _pthread_mutex_lock _pthread_mutex_lock
|
||||||
|
var _pthread_mutex_lock uintptr
|
||||||
|
var pthread_mutex_lockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_lock))
|
||||||
|
|
||||||
|
//go:linkname _pthread_mutex_unlock _pthread_mutex_unlock
|
||||||
|
var _pthread_mutex_unlock uintptr
|
||||||
|
var pthread_mutex_unlockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_unlock))
|
||||||
|
|
||||||
|
//go:linkname _pthread_cond_broadcast _pthread_cond_broadcast
|
||||||
|
var _pthread_cond_broadcast uintptr
|
||||||
|
var pthread_cond_broadcastABI0 = uintptr(unsafe.Pointer(&_pthread_cond_broadcast))
|
||||||
|
|
||||||
|
//go:linkname _pthread_setspecific _pthread_setspecific
|
||||||
|
var _pthread_setspecific uintptr
|
||||||
|
var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific))
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_malloc malloc "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_free free "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_setenv setenv "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_unsetenv unsetenv "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_self pthread_self "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "/usr/lib/libSystem.B.dylib"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "/usr/lib/libSystem.B.dylib"
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_malloc malloc "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_free free "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_setenv setenv "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_abort abort "libc.so.7"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_self pthread_self "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
package fakecgo
|
||||||
|
|
||||||
|
//go:cgo_import_dynamic purego_malloc malloc "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_free free "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_setenv setenv "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_abort abort "libc.so.6"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_self pthread_self "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so.0"
|
||||||
|
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so.0"
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||||
|
|
||||||
|
//go:build darwin || linux || freebsd
|
||||||
|
|
||||||
|
/*
|
||||||
|
trampoline for emulating required C functions for cgo in go (see cgo.go)
|
||||||
|
(we convert cdecl calling convention to go and vice-versa)
|
||||||
|
|
||||||
|
Since we're called from go and call into C we can cheat a bit with the calling conventions:
|
||||||
|
- in go all the registers are caller saved
|
||||||
|
- in C we have a couple of callee saved registers
|
||||||
|
|
||||||
|
=> we can use BX, R12, R13, R14, R15 instead of the stack
|
||||||
|
|
||||||
|
C Calling convention cdecl used here (we only need integer args):
|
||||||
|
1. arg: DI
|
||||||
|
2. arg: SI
|
||||||
|
3. arg: DX
|
||||||
|
4. arg: CX
|
||||||
|
5. arg: R8
|
||||||
|
6. arg: R9
|
||||||
|
We don't need floats with these functions -> AX=0
|
||||||
|
return value will be in AX
|
||||||
|
*/
|
||||||
|
#include "textflag.h"
|
||||||
|
#include "go_asm.h"
|
||||||
|
|
||||||
|
// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
|
||||||
|
|
||||||
|
TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16
|
||||||
|
MOVQ DI, AX
|
||||||
|
MOVQ SI, BX
|
||||||
|
MOVQ ·x_cgo_init_call(SB), DX
|
||||||
|
MOVQ (DX), CX
|
||||||
|
CALL CX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8
|
||||||
|
MOVQ DI, AX
|
||||||
|
MOVQ ·x_cgo_thread_start_call(SB), DX
|
||||||
|
MOVQ (DX), CX
|
||||||
|
CALL CX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8
|
||||||
|
MOVQ DI, AX
|
||||||
|
MOVQ ·x_cgo_setenv_call(SB), DX
|
||||||
|
MOVQ (DX), CX
|
||||||
|
CALL CX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8
|
||||||
|
MOVQ DI, AX
|
||||||
|
MOVQ ·x_cgo_unsetenv_call(SB), DX
|
||||||
|
MOVQ (DX), CX
|
||||||
|
CALL CX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0
|
||||||
|
CALL ·x_cgo_notify_runtime_init_done(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
|
||||||
|
CALL ·x_cgo_bindm(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func setg_trampoline(setg uintptr, g uintptr)
|
||||||
|
TEXT ·setg_trampoline(SB), NOSPLIT, $0-16
|
||||||
|
MOVQ G+8(FP), DI
|
||||||
|
MOVQ setg+0(FP), BX
|
||||||
|
XORL AX, AX
|
||||||
|
CALL BX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT threadentry_trampoline(SB), NOSPLIT, $16
|
||||||
|
MOVQ DI, AX
|
||||||
|
MOVQ ·threadentry_call(SB), DX
|
||||||
|
MOVQ (DX), CX
|
||||||
|
CALL CX
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·call5(SB), NOSPLIT, $0-56
|
||||||
|
MOVQ fn+0(FP), BX
|
||||||
|
MOVQ a1+8(FP), DI
|
||||||
|
MOVQ a2+16(FP), SI
|
||||||
|
MOVQ a3+24(FP), DX
|
||||||
|
MOVQ a4+32(FP), CX
|
||||||
|
MOVQ a5+40(FP), R8
|
||||||
|
|
||||||
|
XORL AX, AX // no floats
|
||||||
|
|
||||||
|
PUSHQ BP // save BP
|
||||||
|
MOVQ SP, BP // save SP inside BP bc BP is callee-saved
|
||||||
|
SUBQ $16, SP // allocate space for alignment
|
||||||
|
ANDQ $-16, SP // align on 16 bytes for SSE
|
||||||
|
|
||||||
|
CALL BX
|
||||||
|
|
||||||
|
MOVQ BP, SP // get SP back
|
||||||
|
POPQ BP // restore BP
|
||||||
|
|
||||||
|
MOVQ AX, ret+48(FP)
|
||||||
|
RET
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user