Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new platform/out: JNI on Linux! #134

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ sled.wasm.map

# nix default result symlink (from nix-build)
/result

# JNI build files
src/os/JniSled.class
src/os/sh_tty_sled_JniSled.h
/sled.jar
1 change: 1 addition & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ include Makefiles/card10.GNUmakefile
include Makefiles/esp32.GNUmakefile
include Makefiles/ndless.GNUmakefile
include Makefiles/emscripten.GNUmakefile
include Makefiles/unix_jni.GNUmakefile

# --- All/Cleaning begins here ---

Expand Down
21 changes: 21 additions & 0 deletions Makefiles/sledconf.unix_jni
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Example sledconf for building sled as a JNI library

# Build with `make sled.jar`

PROJECT := sled

DEBUG := 0

# I've only validated it to work in static form. Dynamic will need extra handling/work in unix_jni.GNUmakefile
STATIC := 1
PLATFORM := unix_jni

# Avoid touching CFLAGS too much.

DEFAULT_OUTMOD := jnibuf
DEFAULT_MODULEDIR := "./modules"
MODULES := $(MODULES_DEFAULT) out_$(DEFAULT_OUTMOD)

# TODO these are useless now. Set them in src/os/JniSled.java instead.
#MATRIX_X := 256
#MATRIX_Y := 256
34 changes: 34 additions & 0 deletions Makefiles/unix_jni.GNUmakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
ifeq ($(PLATFORM),unix_jni)

ifeq (,${JAVA_HOME})
#$(error Please set JAVA_HOME)
JAVA_HOME := /usr/lib/jvm/java-17-openjdk
endif

STATIC := 1

CFLAGS += -fPIC

CFLAGS += -I${JAVA_HOME}/include/
CFLAGS += -I${JAVA_HOME}/include/linux


src/os/sh_tty_sled_JniSled.h src/os/JniSled.class: src/os/JniSled.java
javac -h src/os $^

sh/tty/sled/JniSled.class: src/os/JniSled.class
mkdir -p $(shell dirname $@)
cp $^ $@

JNI_PROJECT := sled

#OBJECTS += sh_tty_sled_JniSled.h

#PROJECT := $(JNI_PROJECT).jar

lib$(PROJECT).so: $(OBJECTS) $(ML_OBJECTS)
$(CC) -shared $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(shell cat $(PLATFORM_LIBS) $(MODULES_STATIC_LIBS) 2>/dev/null || true)

$(PROJECT).jar: lib$(PROJECT).so sh/tty/sled/JniSled.class
zip $@ $^
endif
156 changes: 156 additions & 0 deletions src/modules/out_jnibuf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Dummy output.
//
// Copyright (c) 2021, fridtjof <[email protected]>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include "../os/sh_tty_sled_JniSled.h"

#include <types.h>
#include <timers.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "stdio.h"

#define PPOS(x, y) (x + (y * matx))

static size_t JNI_BUFFER_SIZE;
static jintArray buffers[2];
static jint* working_buffer;
static jint* currentBufferPtr;
static int currentBuffer = -1;
#define NEXTBUFFER ((currentBuffer + 1) % 2)

extern JNIEnv *pJniEnv;
#define JniEnv (*pJniEnv)
extern jobject jo_jni_sled;

static jclass jc_jni_sled;
static jmethodID jm_setCurrentBuffer;
static jfieldID jf_matx;
static jfieldID jf_maty;

static int matx;
static int maty;

void print_any_exceptions() {
if (JniEnv->ExceptionCheck(pJniEnv)) {
// this doesn't actually output anything??
JniEnv->ExceptionDescribe(pJniEnv);
JniEnv->ExceptionClear(pJniEnv);
}
}

void swapBuffers() {
currentBuffer = NEXTBUFFER;
JniEnv->CallVoidMethodA(pJniEnv, jo_jni_sled, jm_setCurrentBuffer, (jvalue *) &buffers[currentBuffer]);

print_any_exceptions();
}

inline unsigned int rgb2uint(RGB color) {
return (color.blue << 0) | (color.green << 8) | (color.red << 16) | (color.alpha << 24);
}

inline RGB uint2rgb(unsigned int color) {
RGB col;
col.blue = (color << 0) & 0xFF;
col.green = (color << 8) & 0xFF;
col.red = (color << 16) & 0xFF;
col.alpha = (color << 24) & 0xFF;

return col;
}

int init(void) {
jc_jni_sled = JniEnv->GetObjectClass(pJniEnv, jo_jni_sled);

// determine sizes
jf_matx = JniEnv->GetFieldID(pJniEnv, jc_jni_sled, "matrixX", "I");
jf_maty = JniEnv->GetFieldID(pJniEnv, jc_jni_sled, "matrixY", "I");
matx = JniEnv->GetIntField(pJniEnv, jo_jni_sled, jf_matx);
maty = JniEnv->GetIntField(pJniEnv, jo_jni_sled, jf_maty);
JNI_BUFFER_SIZE = matx * maty * sizeof(jint);

// allocate output buffers
working_buffer = malloc(JNI_BUFFER_SIZE);
buffers[0] = JniEnv->NewIntArray(pJniEnv, matx * maty);
buffers[1] = JniEnv->NewIntArray(pJniEnv, matx * maty);

// get ready for rendering
jm_setCurrentBuffer = JniEnv->GetMethodID(pJniEnv, jc_jni_sled, "setCurrentBuffer", "([I)V");
swapBuffers();

return 0;
}

int getx(int _modno) {
return matx;
}
int gety(int _modno) {
return maty;
}

static inline void bounds_check(int x, int y) {
assert(x >= 0);
assert(y >= 0);
assert(x < matx);
assert(y < maty);
}

int set(int _modno, int x, int y, RGB color) {
bounds_check(x, y);
working_buffer[PPOS(x, y)] = rgb2uint(color);
return 0;
}

RGB get(int _modno, int x, int y) {
bounds_check(x, y);
return uint2rgb((unsigned int) working_buffer[PPOS(x, y)]);
}

int clear(int _modno) {
memset(working_buffer, 0, JNI_BUFFER_SIZE);
return 0;
}

int render(void) {
// prepare for working on the next frame
currentBufferPtr = JniEnv->GetIntArrayElements(pJniEnv, buffers[NEXTBUFFER], 0 /*ptr bool*/);
memcpy(currentBufferPtr, working_buffer, JNI_BUFFER_SIZE);
JniEnv->ReleaseIntArrayElements(pJniEnv, buffers[NEXTBUFFER], currentBufferPtr, 0);
swapBuffers();
// notify? prob not needed i think?
return 0;
}

oscore_time wait_until(int _modno, oscore_time desired_usec) {
// Hey, we can just delegate work to someone else. Yay!
#ifdef CIMODE
return desired_usec;
#else
return timers_wait_until_core(desired_usec);
#endif
}

void wait_until_break(int _modno) {
#ifndef CIMODE
timers_wait_until_break_core();
#endif
}

void deinit(int _modno) {
// TODO actually do stuff here. Sled and/or jvm won't exit properly.
// maybe this needs some more fiddling in the os_ module too?
}
48 changes: 48 additions & 0 deletions src/os/JniSled.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package sh.tty.sled;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

public class JniSled implements Runnable {
static {
System.loadLibrary("sled");
}

private int matrixX = 256;
private int matrixY = 256;

private int[] currentBuf;

public JniSled(int x, int y) {
matrixX = x;
matrixY = y;
}

public native void main();

@Override
public void run() {
main();
}

public int getMatrixX() {
return matrixX;
}

public int getMatrixY() {
return matrixY;
}

public int[] getCurrentBuffer() {
return currentBuf;
}

// called from out_jnibuf
// TODO: maybe make this trigger a callback optionally?
// could use that to let the user immediately render,
// "pushing" instead of polling
// this would let us have a variable frame rate dictated by sled.
private void setCurrentBuffer(int[] buf) {
currentBuf = buf;
}
}
31 changes: 31 additions & 0 deletions src/os/os_unix_jni.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// os_unix_jni
// you're going to hate this
//
// Copyright (c) 2021, fridtjof <[email protected]>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include "os_unix.c"

#include "sh_tty_sled_JniSled.h"

JNIEnv *pJniEnv;
jobject jo_jni_sled;

JNIEXPORT void JNICALL Java_sh_tty_sled_JniSled_main(JNIEnv * env, jobject obj) {
pJniEnv = env;
jo_jni_sled = obj;

char * args[] = {"sled"};
sled_main(1,args);
}
1 change: 1 addition & 0 deletions src/os/os_unix_jni.libs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-lpthread