JNI attempt 1
This commit is contained in:
parent
072d4f7784
commit
63e3eeba79
@ -2,7 +2,7 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>electrosphere</groupId>
|
||||
<artifactId>sample-cli-java</artifactId>
|
||||
<artifactId>fluid-sim</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<plugins>
|
||||
@ -55,11 +55,31 @@
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<compilerArgs>
|
||||
<arg>--add-modules</arg>
|
||||
<arg>jdk.incubator.vector</arg>
|
||||
<arg>-h</arg>
|
||||
<arg>src/main/c/includes</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile-c-code</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>bash</executable>
|
||||
<arguments>
|
||||
<argument>./src/main/c/compile.sh</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
@ -99,6 +119,6 @@
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<joml.version>1.10.5</joml.version>
|
||||
<lwjgl.version>3.3.2</lwjgl.version>
|
||||
<lwjgl.version>3.2.3</lwjgl.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
27
pom.xml
27
pom.xml
@ -9,7 +9,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<lwjgl.version>3.3.2</lwjgl.version>
|
||||
<lwjgl.version>3.2.3</lwjgl.version>
|
||||
<joml.version>1.10.5</joml.version>
|
||||
</properties>
|
||||
|
||||
@ -133,7 +133,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
@ -164,11 +163,31 @@
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<compilerArgs>
|
||||
<arg>--add-modules</arg>
|
||||
<arg>jdk.incubator.vector</arg>
|
||||
<arg>-h</arg>
|
||||
<arg>src/main/c/includes</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile-c-code</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>bash</executable>
|
||||
<arguments>
|
||||
<argument>./src/main/c/compile.sh</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
BIN
shared-folder/libfluidsim.dll
Normal file
BIN
shared-folder/libfluidsim.dll
Normal file
Binary file not shown.
62
src/main/c/compile.sh
Normal file
62
src/main/c/compile.sh
Normal file
@ -0,0 +1,62 @@
|
||||
cd ./src/main/c
|
||||
|
||||
LIB_ENDING=".so"
|
||||
BASE_INCLUDE_DIR=""
|
||||
OS_INCLUDE_DIR=""
|
||||
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
#linux
|
||||
LIB_ENDING=".so"
|
||||
BASE_INCLUDE_DIR="${JAVA_HOME}/include"
|
||||
OS_INCLUDE_DIR="${JAVA_HOME}/include/linux"
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# Mac OSX
|
||||
LIB_ENDING=".so"
|
||||
elif [[ "$OSTYPE" == "cygwin" ]]; then
|
||||
# POSIX compatibility layer and Linux environment emulation for Windows
|
||||
LIB_ENDING=".dll"
|
||||
elif [[ "$OSTYPE" == "msys" ]]; then
|
||||
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
|
||||
LIB_ENDING=".dll"
|
||||
BASE_INCLUDE_DIR="${JAVA_HOME}/include"
|
||||
OS_INCLUDE_DIR="${JAVA_HOME}/include/win32"
|
||||
elif [[ "$OSTYPE" == "win32" ]]; then
|
||||
# I'm not sure this can happen.
|
||||
LIB_ENDING=".dll"
|
||||
elif [[ "$OSTYPE" == "freebsd"* ]]; then
|
||||
# ...
|
||||
LIB_ENDING=".so"
|
||||
else
|
||||
# Unknown.
|
||||
LIB_ENDING=".so"
|
||||
fi
|
||||
|
||||
# echo $PWD
|
||||
|
||||
#clean compile dir
|
||||
rm -f ./*.o
|
||||
rm -f ./*.so
|
||||
rm -f ./*.dll
|
||||
|
||||
|
||||
#compile object files
|
||||
COMPILE_FLAGS="-c -fPIC -m64"
|
||||
INPUT_FILES="./fluidsim.c"
|
||||
OUTPUT_FILE="./fluidsim.o"
|
||||
gcc $COMPILE_FLAGS -I"$BASE_INCLUDE_DIR" -I"$OS_INCLUDE_DIR" $INPUT_FILES -o $OUTPUT_FILE
|
||||
|
||||
|
||||
|
||||
#compile shared object file
|
||||
OUTPUT_FILE="libfluidsim$LIB_ENDING"
|
||||
COMPILE_FLAGS="-shared"
|
||||
INPUT_FILES="fluidsim.o"
|
||||
gcc $COMPILE_FLAGS $INPUT_FILES -o $OUTPUT_FILE
|
||||
|
||||
#move to resources
|
||||
mv "./libfluidsim$LIB_ENDING" "../../../shared-folder/"
|
||||
|
||||
#clean compile dir
|
||||
rm -f ./*.o
|
||||
rm -f ./*.so
|
||||
rm -f ./*.dll
|
||||
237
src/main/c/fluidsim.c
Normal file
237
src/main/c/fluidsim.c
Normal file
@ -0,0 +1,237 @@
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
#define SWAP(x0,x) {float *tmp=x0;x0=x;x=tmp;}
|
||||
#define IX(i,j,k) ((i)+(N)*(j)+(N*N)*(k))
|
||||
|
||||
#define LINEARSOLVERTIMES 20
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void diffuse(int N, int b, float * x, float * x0, float diff, float dt);
|
||||
void advect(int N, int b, float * d, float * d0, float * u, float * v, float * w, float dt);
|
||||
void project(int N, float * u, float * v, float * w, float * p, float * div);
|
||||
void set_bnd(int N, int b, float * x);
|
||||
void dens_step(int N, float * x, float * x0, float * u, float * v, float * w, float diff, float dt);
|
||||
void vel_step(int N, float * u, float * v, float * w, float * u0, float * v0, float * w0, float visc, float dt);
|
||||
void lin_solve(int N, int b, float* x, float* x0, float a, float c);
|
||||
|
||||
JNIEXPORT void JNICALL Java_electrosphere_FluidSim_simulate(
|
||||
JNIEnv * env,
|
||||
jobject this,
|
||||
jint DIM_X,
|
||||
jint DIM_Y,
|
||||
jint DIM_Z,
|
||||
jfloatArray jx,
|
||||
jfloatArray jx0,
|
||||
jfloatArray ju,
|
||||
jfloatArray jv,
|
||||
jfloatArray jw,
|
||||
jfloatArray ju0,
|
||||
jfloatArray jv0,
|
||||
jfloatArray jw0,
|
||||
jfloat DIFFUSION_RATE,
|
||||
jfloat VISCOSITY_RATE,
|
||||
jfloat timestep){
|
||||
jboolean isCopy;
|
||||
float * x = (*env)->GetFloatArrayElements(env,jx,&isCopy);
|
||||
float * x0 = (*env)->GetFloatArrayElements(env,jx0,&isCopy);
|
||||
float * u = (*env)->GetFloatArrayElements(env,ju,&isCopy);
|
||||
float * v = (*env)->GetFloatArrayElements(env,jv,&isCopy);
|
||||
float * w = (*env)->GetFloatArrayElements(env,jw,&isCopy);
|
||||
float * u0 = (*env)->GetFloatArrayElements(env,ju0,&isCopy);
|
||||
float * v0 = (*env)->GetFloatArrayElements(env,jv0,&isCopy);
|
||||
float * w0 = (*env)->GetFloatArrayElements(env,jw0,&isCopy);
|
||||
vel_step(DIM_X, u, v, w, u0, v0, w0, VISCOSITY_RATE, timestep);
|
||||
dens_step(DIM_X, x, x0, u, v, w, DIFFUSION_RATE, timestep);
|
||||
(*env)->SetFloatArrayRegion(env,jx,0,DIM_X*DIM_X*DIM_X,x);
|
||||
(*env)->SetFloatArrayRegion(env,jx0,0,DIM_X*DIM_X*DIM_X,x0);
|
||||
(*env)->SetFloatArrayRegion(env,ju,0,DIM_X*DIM_X*DIM_X,u);
|
||||
(*env)->SetFloatArrayRegion(env,jv,0,DIM_X*DIM_X*DIM_X,v);
|
||||
(*env)->SetFloatArrayRegion(env,jw,0,DIM_X*DIM_X*DIM_X,w);
|
||||
(*env)->SetFloatArrayRegion(env,ju0,0,DIM_X*DIM_X*DIM_X,u0);
|
||||
(*env)->SetFloatArrayRegion(env,jv0,0,DIM_X*DIM_X*DIM_X,v0);
|
||||
(*env)->SetFloatArrayRegion(env,jw0,0,DIM_X*DIM_X*DIM_X,w0);
|
||||
// for(int i=0; i<DIM_X; i++){for(int j=0; j<DIM_X; j++){for(int k=0; k<DIM_X; k++){
|
||||
// (*env)->SetFloatArrayRegion(env,jx,0,DIM_X*DIM_X*DIM_X,x);
|
||||
// // jx[IX(i,j,k)] = x[IX(i,j,k)];
|
||||
// }}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
printf("Hello World from Project Panama Baeldung Article");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void diffuse(int N, int b, float * x, float * x0, float diff, float dt){
|
||||
float a=dt*diff*N*N*N;
|
||||
lin_solve(N, b, x, x0, a, 1+6*a);
|
||||
}
|
||||
|
||||
void advect(int N, int b, float * d, float * d0, float * u, float * v, float * w, float dt){
|
||||
int i, j, k, i0, j0, k0, i1, j1, k1;
|
||||
float x, y, z, s0, t0, s1, t1, u1, u0, dtx,dty,dtz;
|
||||
|
||||
dtx=dty=dtz=dt*N;
|
||||
|
||||
for ( i=1 ; i<N-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<N-1 ; k++ ) {
|
||||
x = i-dtx*u[IX(i,j,k)]; y = j-dty*v[IX(i,j,k)]; z = k-dtz*w[IX(i,j,k)];
|
||||
if (x<0.5f) x=0.5f; if (x>N+0.5f) x=N+0.5f; i0=(int)x; i1=i0+1;
|
||||
if (y<0.5f) y=0.5f; if (y>N+0.5f) y=N+0.5f; j0=(int)y; j1=j0+1;
|
||||
if (z<0.5f) z=0.5f; if (z>N+0.5f) z=N+0.5f; k0=(int)z; k1=k0+1;
|
||||
|
||||
s1 = x-i0; s0 = 1-s1; t1 = y-j0; t0 = 1-t1; u1 = z-k0; u0 = 1-u1;
|
||||
if(i0 >= N){
|
||||
i0 = N - 1;
|
||||
}
|
||||
if(j0 >= N){
|
||||
j0 = N - 1;
|
||||
}
|
||||
if(k0 >= N){
|
||||
k0 = N - 1;
|
||||
}
|
||||
if(i1 >= N){
|
||||
i1 = N - 1;
|
||||
}
|
||||
if(j1 >= N){
|
||||
j1 = N - 1;
|
||||
}
|
||||
if(k1 >= N){
|
||||
k1 = N - 1;
|
||||
}
|
||||
d[IX(i,j,k)] = s0*(t0*u0*d0[IX(i0,j0,k0)]+t1*u0*d0[IX(i0,j1,k0)]+t0*u1*d0[IX(i0,j0,k1)]+t1*u1*d0[IX(i0,j1,k1)])+
|
||||
s1*(t0*u0*d0[IX(i1,j0,k0)]+t1*u0*d0[IX(i1,j1,k0)]+t0*u1*d0[IX(i1,j0,k1)]+t1*u1*d0[IX(i1,j1,k1)]);
|
||||
}}}
|
||||
set_bnd(N, b, d);
|
||||
}
|
||||
|
||||
void dens_step(int N, float * x, float * x0, float * u, float * v, float * w, float diff, float dt){
|
||||
// add_source ( N, x, x0, dt );
|
||||
SWAP ( x0, x ); diffuse ( N, 0, x, x0, diff, dt );
|
||||
SWAP ( x0, x ); advect ( N, 0, x, x0, u, v, w, dt );
|
||||
}
|
||||
|
||||
void vel_step(int N, float * u, float * v, float * w, float * u0, float * v0, float * w0, float visc, float dt){
|
||||
// add_source ( N, u, u0, dt ); add_source ( N, v, v0, dt );
|
||||
// SWAP ( u0, u ); diffuse ( N, 1, u, u0, visc, dt );
|
||||
// SWAP ( v0, v ); diffuse ( N, 2, v, v0, visc, dt );
|
||||
// project ( N, u, v, w, u0, v0 );
|
||||
// SWAP ( u0, u ); SWAP ( v0, v );
|
||||
// advect ( N, 1, u, u0, u0, v0, dt ); advect ( N, 2, v, v0, u0, v0, dt );
|
||||
// project ( N, u, v, w, u0, v0 );
|
||||
|
||||
// add_source(N, v, x, dt);
|
||||
SWAP(u0, u);
|
||||
diffuse(N, 1, u, u0, visc, dt);
|
||||
SWAP(v0, v);
|
||||
diffuse(N, 2, v, v0, visc, dt);
|
||||
SWAP(w0, w);
|
||||
diffuse(N, 3, w, w0, visc, dt);
|
||||
project(N, u, v, w, u0, v0);
|
||||
SWAP(u0, u);
|
||||
SWAP(v0, v);
|
||||
SWAP(w0, w);
|
||||
advect(N, 1, u, u0, u0, v0, w0, dt);
|
||||
advect(N, 2, v, v0, u0, v0, w0, dt);
|
||||
advect(N, 3, w, w0, u0, v0, w0, dt);
|
||||
project(N, u, v, w, u0, v0);
|
||||
}
|
||||
|
||||
void project(int N, float * u, float * v, float * w, float * p, float * div){
|
||||
int i, j, k;
|
||||
|
||||
for ( i=1 ; i<N-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<N-1 ; k++ ) {
|
||||
div[IX(i,j,k)] = (float)(-1.0/3.0*((u[IX(i+1,j,k)]-u[IX(i-1,j,k)])/N+(v[IX(i,j+1,k)]-v[IX(i,j-1,k)])/N+(w[IX(i,j,k+1)]-w[IX(i,j,k-1)])/N));
|
||||
p[IX(i,j,k)] = 0;
|
||||
}}}
|
||||
|
||||
set_bnd(N, 0, div);
|
||||
set_bnd(N, 0, p);
|
||||
|
||||
lin_solve(N, 0, p, div, 1, 6);
|
||||
|
||||
for ( i=1 ; i<N-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<N-1 ; k++ ) {
|
||||
u[IX(i,j,k)] -= 0.5f*N*(p[IX(i+1,j,k)]-p[IX(i-1,j,k)]);
|
||||
v[IX(i,j,k)] -= 0.5f*N*(p[IX(i,j+1,k)]-p[IX(i,j-1,k)]);
|
||||
w[IX(i,j,k)] -= 0.5f*N*(p[IX(i,j,k+1)]-p[IX(i,j,k-1)]);
|
||||
}}}
|
||||
|
||||
set_bnd(N, 1, u);
|
||||
set_bnd(N, 2, v);
|
||||
set_bnd(N, 3, w);
|
||||
}
|
||||
|
||||
void lin_solve(int N, int b, float* x, float* x0, float a, float c){
|
||||
int i, j, k, l;
|
||||
|
||||
// iterate the solver
|
||||
for ( l=0 ; l<LINEARSOLVERTIMES ; l++ ) {
|
||||
// update for each cell
|
||||
for ( i=1 ; i<N-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<N-1 ; k++ ) {
|
||||
x[IX(i,j,k)] = (x0[IX(i,j,k)] + a*(x[IX(i-1,j,k)]+x[IX(i+1,j,k)]+x[IX(i,j-1,k)]+x[IX(i,j+1,k)]+x[IX(i,j,k-1)]+x[IX(i,j,k+1)]))/c;
|
||||
}}}
|
||||
set_bnd(N, b, x);
|
||||
}
|
||||
}
|
||||
|
||||
// void set_bnd ( int N, int b, float * x ){
|
||||
// int i;
|
||||
// // for ( i=1 ; i<=N ; i++ ) {
|
||||
// // x[IX(0 ,i)] = b==1 ? -x[IX(1,i)] : x[IX(1,i)];
|
||||
// // x[IX(N+1,i)] = b==1 ? -x[IX(N,i)] : x[IX(N,i)];
|
||||
// // x[IX(i,0 )] = b==2 ? -x[IX(i,1)] : x[IX(i,1)];
|
||||
// // x[IX(i,N+1)] = b==2 ? -x[IX(i,N)] : x[IX(i,N)];
|
||||
// // }
|
||||
// // x[IX(0 ,0 )] = 0.5*(x[IX(1,0 )]+x[IX(0 ,1)]);
|
||||
// // x[IX(0 ,N+1)] = 0.5*(x[IX(1,N+1)]+x[IX(0 ,N )]);
|
||||
// // x[IX(N+1,0 )] = 0.5*(x[IX(N,0 )]+x[IX(N+1,1)]);
|
||||
// // x[IX(N+1,N+1)] = 0.5*(x[IX(N,N+1)]+x[IX(N+1,N )]);
|
||||
// }
|
||||
|
||||
void set_bnd(int N, int b, float * target){
|
||||
int DIM = N;
|
||||
for(int x=1; x < DIM-1; x++){
|
||||
for(int y = 1; y < DIM-1; y++){
|
||||
//((x)+(DIM)*(y) + (DIM)*(DIM)*(z))
|
||||
target[0 + DIM * x + DIM * DIM * y] = b==1 ? -target[1 + DIM * x + DIM * DIM * y] : target[1 + DIM * x + DIM * DIM * y];
|
||||
target[IX(DIM-1,x,y)] = b==1 ? -target[IX(DIM-2,x,y)] : target[IX(DIM-2,x,y)];
|
||||
target[IX(x,0,y)] = b==2 ? -target[IX(x,1,y)] : target[IX(x,1,y)];
|
||||
target[IX(x,DIM-1,y)] = b==2 ? -target[IX(x,DIM-2,y)] : target[IX(x,DIM-2,y)];
|
||||
target[IX(x,y,0)] = b==3 ? -target[IX(x,y,1)] : target[IX(x,y,1)];
|
||||
target[IX(x,y,DIM-1)] = b==3 ? -target[IX(x,y,DIM-2)] : target[IX(x,y,DIM-2)];
|
||||
}
|
||||
}
|
||||
for(int x = 1; x < DIM-1; x++){
|
||||
target[IX(x,0,0)] = (float)(0.5f * (target[IX(x,1,0)] + target[IX(x,0,1)]));
|
||||
target[IX(x,DIM-1,0)] = (float)(0.5f * (target[IX(x,DIM-2,0)] + target[IX(x,DIM-1,1)]));
|
||||
target[IX(x,0,DIM-1)] = (float)(0.5f * (target[IX(x,1,DIM-1)] + target[IX(x,0,DIM-2)]));
|
||||
target[IX(x,DIM-1,DIM-1)] = (float)(0.5f * (target[IX(x,DIM-2,DIM-1)] + target[IX(x,DIM-1,DIM-2)]));
|
||||
|
||||
target[IX(0,x,0)] = (float)(0.5f * (target[IX(1,x,0)] + target[IX(0,x,1)]));
|
||||
target[IX(DIM-1,x,0)] = (float)(0.5f * (target[IX(DIM-2,x,0)] + target[IX(DIM-1,x,1)]));
|
||||
target[IX(0,x,DIM-1)] = (float)(0.5f * (target[IX(1,x,DIM-1)] + target[IX(0,x,DIM-2)]));
|
||||
target[IX(DIM-1,x,DIM-1)] = (float)(0.5f * (target[IX(DIM-2,x,DIM-1)] + target[IX(DIM-1,x,DIM-2)]));
|
||||
|
||||
|
||||
target[IX(0,0,x)] = (float)(0.5f * (target[IX(1,0,x)] + target[IX(0,1,x)]));
|
||||
target[IX(DIM-1,0,x)] = (float)(0.5f * (target[IX(DIM-2,0,x)] + target[IX(DIM-1,1,x)]));
|
||||
target[IX(0,DIM-1,x)] = (float)(0.5f * (target[IX(1,DIM-1,x)] + target[IX(0,DIM-2,x)]));
|
||||
target[IX(DIM-1,DIM-1,x)] = (float)(0.5f * (target[IX(DIM-2,DIM-1,x)] + target[IX(DIM-1,DIM-2,x)]));
|
||||
|
||||
}
|
||||
target[IX(0,0,0)] = (float)((target[IX(1,0,0)]+target[IX(0,1,0)]+target[IX(0,0,1)])/3.0);
|
||||
target[IX(DIM-1,0,0)] = (float)((target[IX(DIM-2,0,0)]+target[IX(DIM-1,1,0)]+target[IX(DIM-1,0,1)])/3.0);
|
||||
target[IX(0,DIM-1,0)] = (float)((target[IX(1,DIM-1,0)]+target[IX(0,DIM-2,0)]+target[IX(0,DIM-1,1)])/3.0);
|
||||
target[IX(0,0,DIM-1)] = (float)((target[IX(0,0,DIM-2)]+target[IX(1,0,DIM-1)]+target[IX(0,1,DIM-1)])/3.0);
|
||||
target[IX(DIM-1,DIM-1,0)] = (float)((target[IX(DIM-2,DIM-1,0)]+target[IX(DIM-1,DIM-2,0)]+target[IX(DIM-1,DIM-1,1)])/3.0);
|
||||
target[IX(0,DIM-1,DIM-1)] = (float)((target[IX(1,DIM-1,DIM-1)]+target[IX(0,DIM-2,DIM-1)]+target[IX(0,DIM-1,DIM-2)])/3.0);
|
||||
target[IX(DIM-1,0,DIM-1)] = (float)((target[IX(DIM-1,0,DIM-2)]+target[IX(DIM-2,0,DIM-1)]+target[IX(DIM-1,1,DIM-1)])/3.0);
|
||||
target[IX(DIM-1,DIM-1,DIM-1)] = (float)((target[IX(DIM-1,DIM-1,DIM-2)]+target[IX(DIM-1,DIM-2,DIM-1)]+target[IX(DIM-1,DIM-1,DIM-2)])/3.0);
|
||||
}
|
||||
31
src/main/c/includes/electrosphere_FluidSim.h
Normal file
31
src/main/c/includes/electrosphere_FluidSim.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class electrosphere_FluidSim */
|
||||
|
||||
#ifndef _Included_electrosphere_FluidSim
|
||||
#define _Included_electrosphere_FluidSim
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef electrosphere_FluidSim_DIM
|
||||
#define electrosphere_FluidSim_DIM 18L
|
||||
#undef electrosphere_FluidSim_DIFFUSION_CONSTANT
|
||||
#define electrosphere_FluidSim_DIFFUSION_CONSTANT 1.0E-4f
|
||||
#undef electrosphere_FluidSim_VISCOSITY_CONSTANT
|
||||
#define electrosphere_FluidSim_VISCOSITY_CONSTANT 1.0E-4f
|
||||
#undef electrosphere_FluidSim_LINEARSOLVERTIMES
|
||||
#define electrosphere_FluidSim_LINEARSOLVERTIMES 20L
|
||||
#undef electrosphere_FluidSim_GRAVITY
|
||||
#define electrosphere_FluidSim_GRAVITY -10000.0f
|
||||
/*
|
||||
* Class: electrosphere_FluidSim
|
||||
* Method: simulate
|
||||
* Signature: (III[F[F[F[F[F[F[F[FFFF)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_electrosphere_FluidSim_simulate
|
||||
(JNIEnv *, jobject, jint, jint, jint, jfloatArray, jfloatArray, jfloatArray, jfloatArray, jfloatArray, jfloatArray, jfloatArray, jfloatArray, jfloat, jfloat, jfloat);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -9,36 +9,21 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.incubator.foreign.MemorySegment;
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.VectorMask;
|
||||
import jdk.incubator.vector.VectorOperators;
|
||||
import jdk.incubator.vector.VectorOperators.Associative;
|
||||
|
||||
import org.joml.Vector2i;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import electrosphere.opencl.CLBuffer;
|
||||
import electrosphere.opencl.CLCommandQueue;
|
||||
import electrosphere.opencl.CLContext;
|
||||
import electrosphere.opencl.CLDevice;
|
||||
import electrosphere.opencl.CLEvent;
|
||||
import electrosphere.opencl.CLImage;
|
||||
import electrosphere.opencl.CLKernel;
|
||||
import electrosphere.opencl.CLPlatform;
|
||||
import electrosphere.opencl.CLProgram;
|
||||
import electrosphere.opencl.CLReadImageResult;
|
||||
import electrosphere.opencl.CLUtilities;
|
||||
import electrosphere.opencl.LWJGLContext;
|
||||
|
||||
/**
|
||||
* Simulates a fluid via opencl
|
||||
*/
|
||||
public class FluidSim {
|
||||
|
||||
static {
|
||||
System.out.println(System.getProperty("user.dir"));
|
||||
System.load(System.getProperty("user.dir") + "/shared-folder/libfluidsim.dll");
|
||||
}
|
||||
|
||||
public static final int DIM = 18;
|
||||
|
||||
float[] x = new float[DIM * DIM * DIM];
|
||||
@ -118,10 +103,11 @@ public class FluidSim {
|
||||
}
|
||||
}
|
||||
|
||||
simulate(DIM, DIM, DIM, x, x0, u, v, w, u0, v0, w0, DIFFUSION_CONSTANT, VISCOSITY_CONSTANT, timestep);
|
||||
|
||||
vel_step(DIM, DIM, DIM, u, v, w, u0, v0, w0, VISCOSITY_CONSTANT, timestep);
|
||||
// vel_step(DIM, DIM, DIM, u, v, w, u0, v0, w0, VISCOSITY_CONSTANT, timestep);
|
||||
|
||||
dens_step(DIM, DIM, DIM, x, x0, u, v, w, DIFFUSION_CONSTANT, timestep);
|
||||
// dens_step(DIM, DIM, DIM, x, x0, u, v, w, DIFFUSION_CONSTANT, timestep);
|
||||
|
||||
sum();
|
||||
}
|
||||
@ -144,7 +130,7 @@ public class FluidSim {
|
||||
void diffuse(int M, int N, int O, int b, float[] x, float[] x0, float diff, float dt){
|
||||
int max = Math.max(Math.max(M, N), Math.max(N, O));
|
||||
float a=dt*diff*max*max*max;
|
||||
linSolveJacobian(M, N, O, b, x, x0, a, 1+6*a);
|
||||
lin_solve(M, N, O, b, x, x0, a, 1+6*a);
|
||||
}
|
||||
|
||||
void setBounds(float[] target, int b){
|
||||
@ -245,7 +231,7 @@ public class FluidSim {
|
||||
setBounds(div, 0);
|
||||
setBounds(p, 0);
|
||||
|
||||
linSolveJacobian(M, N, O, 0, p, div, 1, 6);
|
||||
lin_solve(M, N, O, 0, p, div, 1, 6);
|
||||
|
||||
for ( i=1 ; i<M-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<O-1 ; k++ ) {
|
||||
u[IX(i,j,k)] -= 0.5f*M*(p[IX(i+1,j,k)]-p[IX(i-1,j,k)]);
|
||||
@ -309,6 +295,23 @@ public class FluidSim {
|
||||
// System.out.println(sum[0] + " " + sum[1] + " " + sum[2] + " " + sum[3]);
|
||||
}
|
||||
|
||||
private native void simulate(
|
||||
int DIM_X,
|
||||
int DIM_Y,
|
||||
int DIM_Z,
|
||||
float[] x,
|
||||
float[] x0,
|
||||
float[] u,
|
||||
float[] v,
|
||||
float[] w,
|
||||
float[] u0,
|
||||
float[] v0,
|
||||
float[] w0,
|
||||
float DIFFUSION_CONSTANT,
|
||||
float VISCOSITY_CONSTANT,
|
||||
float timestep
|
||||
);
|
||||
|
||||
public float[] getData(){
|
||||
return x;
|
||||
}
|
||||
@ -344,81 +347,4 @@ public class FluidSim {
|
||||
}
|
||||
}
|
||||
|
||||
static final int LANE_WIDTH = 8;
|
||||
void linSolveJacobian(int M, int N, int O, int b, float[] x, float x0[], float a, float c){
|
||||
//x contains the solution to the problem
|
||||
//x0 contains A
|
||||
|
||||
// float[] a = new float[]{
|
||||
// 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
|
||||
// };
|
||||
// FloatVector vec = FloatVector.fromArray(FloatVector.SPECIES_128, a, 0);
|
||||
// FloatVector finalVec = vec.add(3);
|
||||
// float[] b = finalVec.toArray();
|
||||
// for(int i = 0; i < b.length; i++){
|
||||
// System.out.println(b[i]);
|
||||
// }
|
||||
float[] vectorArrView;
|
||||
float[] srcArr, destArr;
|
||||
for(int k = 0; k < LINEARSOLVERTIMES; k++){
|
||||
if(k / 2 == 0){
|
||||
srcArr = x;
|
||||
destArr = jacobiAltArray;
|
||||
} else {
|
||||
srcArr = jacobiAltArray;
|
||||
destArr = x;
|
||||
}
|
||||
for(int i = 0; i < vectorOffsetMap.length; i += LANE_WIDTH){
|
||||
if(i + LANE_WIDTH < vectorOffsetMap.length){
|
||||
|
||||
// for ( i=1 ; i<M-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<O-1 ; k++ ) {
|
||||
// x[IX(i,j,k)] = (x0[IX(i,j,k)] + a*(x[IX(i-1,j,k)]+x[IX(i+1,j,k)]+x[IX(i,j-1,k)]+x[IX(i,j+1,k)]+x[IX(i,j,k-1)]+x[IX(i,j,k+1)]))/c;
|
||||
// }}}
|
||||
|
||||
// adderVector = FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXN,i);
|
||||
// x0Vector = FloatVector.fromArray(FloatVector.SPECIES_256,x0,0,vectorOffsetMap,i);
|
||||
vectorArrView = FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXN,i)
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXP,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapYN,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapYP,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapZN,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapZP,i))
|
||||
.mul(a)
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x0,0,vectorOffsetMap,i))
|
||||
.div(c).toArray();
|
||||
|
||||
for(int l = 0; l < LANE_WIDTH; l++){
|
||||
x[vectorOffsetMap[i+l]] = vectorArrView[l];
|
||||
}
|
||||
} else {
|
||||
int numLeft = vectorOffsetMap.length - i;
|
||||
|
||||
VectorMask<Float> mask = FloatVector.SPECIES_256.indexInRange(O, numLeft);
|
||||
|
||||
// for ( i=1 ; i<M-1 ; i++ ) { for ( j=1 ; j<N-1 ; j++ ) { for ( k=1 ; k<O-1 ; k++ ) {
|
||||
// x[IX(i,j,k)] = (x0[IX(i,j,k)] + a*(x[IX(i-1,j,k)]+x[IX(i+1,j,k)]+x[IX(i,j-1,k)]+x[IX(i,j+1,k)]+x[IX(i,j,k-1)]+x[IX(i,j,k+1)]))/c;
|
||||
// }}}
|
||||
|
||||
// adderVector = FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXN,i,mask);
|
||||
// x0Vector = FloatVector.fromArray(FloatVector.SPECIES_256,x0,0,vectorOffsetMap,i,mask);
|
||||
vectorArrView = FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXN,i,mask)
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapXP,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapYN,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapYP,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapZN,i))
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x,0,vectorOffsetMapZP,i))
|
||||
.mul(a)
|
||||
.add(FloatVector.fromArray(FloatVector.SPECIES_256,x0,0,vectorOffsetMap,i,mask))
|
||||
.div(c).toArray();
|
||||
|
||||
for(int l = 0; l < numLeft; l++){
|
||||
x[vectorOffsetMap[i+l]] = vectorArrView[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
setBounds(destArr, b);
|
||||
}
|
||||
//x[IX(i,j,k)] = (x0[IX(i,j,k)] + a*(x[IX(i-1,j,k)]+x[IX(i+1,j,k)]+x[IX(i,j-1,k)]+x[IX(i,j+1,k)]+x[IX(i,j,k-1)]+x[IX(i,j,k+1)]))/c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,28 +15,32 @@ import electrosphere.render.Mesh;
|
||||
public class Main {
|
||||
|
||||
public static void main(String args[]){
|
||||
GLFWContext.init();
|
||||
FluidSim sim = new FluidSim();
|
||||
sim.setup();
|
||||
Mesh.meshInitially(sim);
|
||||
int i = 0;
|
||||
long time = 0;
|
||||
long lastTime = 0;
|
||||
while(true){
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
lastTime = System.currentTimeMillis();
|
||||
sim.simulate(i,0.001f);
|
||||
time = time + (System.currentTimeMillis() - lastTime);
|
||||
Mesh.remesh(sim);
|
||||
GLFWContext.redraw();
|
||||
i++;
|
||||
if(i == 1000){
|
||||
System.out.println(time / 1000.0);
|
||||
try {
|
||||
GLFWContext.init();
|
||||
FluidSim sim = new FluidSim();
|
||||
sim.setup();
|
||||
Mesh.meshInitially(sim);
|
||||
int i = 0;
|
||||
long time = 0;
|
||||
long lastTime = 0;
|
||||
while(true){
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
lastTime = System.currentTimeMillis();
|
||||
sim.simulate(i,0.001f);
|
||||
time = time + (System.currentTimeMillis() - lastTime);
|
||||
Mesh.remesh(sim);
|
||||
GLFWContext.redraw();
|
||||
i++;
|
||||
if(i == 1000){
|
||||
System.out.println(time / 1000.0);
|
||||
}
|
||||
}
|
||||
} catch(Throwable ex){
|
||||
ex.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,89 +0,0 @@
|
||||
package electrosphere;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joml.Vector2i;
|
||||
import org.lwjgl.*;
|
||||
import org.lwjgl.glfw.*;
|
||||
import org.lwjgl.opencl.*;
|
||||
import org.lwjgl.system.*;
|
||||
|
||||
import electrosphere.opencl.CLBuffer;
|
||||
import electrosphere.opencl.CLCommandQueue;
|
||||
import electrosphere.opencl.CLContext;
|
||||
import electrosphere.opencl.CLDevice;
|
||||
import electrosphere.opencl.CLEvent;
|
||||
import electrosphere.opencl.CLImage;
|
||||
import electrosphere.opencl.CLKernel;
|
||||
import electrosphere.opencl.CLPlatform;
|
||||
import electrosphere.opencl.CLProgram;
|
||||
import electrosphere.opencl.CLReadImageResult;
|
||||
import electrosphere.opencl.CLUtilities;
|
||||
import electrosphere.opencl.LWJGLContext;
|
||||
|
||||
import static org.lwjgl.glfw.Callbacks.*;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opencl.CL10.*;
|
||||
import static org.lwjgl.opencl.KHRICD.*;
|
||||
import static org.lwjgl.system.MemoryStack.*;
|
||||
import static org.lwjgl.system.MemoryUtil.*;
|
||||
import static org.lwjgl.glfw.GLFWNativeGLX.*;
|
||||
import static org.lwjgl.glfw.GLFWNativeWGL.*;
|
||||
import static org.lwjgl.glfw.GLFWNativeX11.*;
|
||||
import static org.lwjgl.opencl.CL10GL.*;
|
||||
import static org.lwjgl.opencl.KHRGLSharing.*;
|
||||
import static org.lwjgl.opengl.ARBCLEvent.*;
|
||||
import static org.lwjgl.opengl.CGL.*;
|
||||
import static org.lwjgl.opengl.GL30C.*;
|
||||
import static org.lwjgl.opengl.WGL.*;
|
||||
|
||||
public class MyTest {
|
||||
|
||||
//Good reference: https://www.nersc.gov/assets/pubs_presos/MattsonTutorialSC14.pdf
|
||||
//Khronos api reference cheatsheet: https://www.khronos.org/files/opencl30-reference-guide.pdf
|
||||
//error code reference: https://streamhpc.com/blog/2013-04-28/opencl-error-codes/
|
||||
//relevant: https://blog.lwjgl.org/memory-management-in-lwjgl-3/
|
||||
//be mindful of: https://www.baeldung.com/java-memory-leaks
|
||||
|
||||
public static void run(){
|
||||
|
||||
|
||||
FluidSim sim = new FluidSim();
|
||||
|
||||
sim.setup();
|
||||
|
||||
double deltaTime = 0.0f;
|
||||
double lastFrame = 0.0f;
|
||||
double frameRate = 0.0f;
|
||||
|
||||
GLFW.glfwInit();
|
||||
|
||||
int iterations = 0;
|
||||
while(true){
|
||||
|
||||
sim.simulate(1, 0.2f);
|
||||
|
||||
//framerate calculations
|
||||
double currentTime = glfwGetTime();
|
||||
deltaTime = currentTime - lastFrame;
|
||||
frameRate = 1.0 / deltaTime;
|
||||
lastFrame = currentTime;
|
||||
|
||||
iterations++;
|
||||
// System.out.print("\r" + currentTime + " " + frameRate + " _ " + iterations + " _ " + Runtime.getRuntime().totalMemory() / 1024 / 1024);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.opencl.CL30;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl buffer
|
||||
*/
|
||||
public class CLBuffer {
|
||||
|
||||
//The pointer to the buffer
|
||||
long pointer;
|
||||
|
||||
/**
|
||||
* Creates a opencl buffer with a specified size
|
||||
* @param context The context to create the buffer under
|
||||
* @param flags The flags for the buffer
|
||||
* @param size The size of the buffer
|
||||
*/
|
||||
protected CLBuffer(CLContext context, long flags, long size){
|
||||
pointer = CL30.clCreateBuffer(context.getPointer(), flags, size, context.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an opencl buffer based on a provided buffer
|
||||
* @param context The context to create the buffer under
|
||||
* @param flags The flags for the buffer
|
||||
* @param hostBuffer The cpu buffer to base the opencl buffer off of
|
||||
*/
|
||||
protected CLBuffer(CLContext context, long flags, IntBuffer hostBuffer){
|
||||
pointer = CL30.clCreateBuffer(context.getPointer(), flags, hostBuffer, context.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,434 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector2i;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl command queue
|
||||
*/
|
||||
public class CLCommandQueue {
|
||||
|
||||
//The lwjgl context
|
||||
LWJGLContext lwjglContext;
|
||||
|
||||
//The pointer to the command queue
|
||||
long pointer;
|
||||
|
||||
/**
|
||||
* Creates a command queue for a provided context
|
||||
* @param context The context
|
||||
*/
|
||||
protected CLCommandQueue(LWJGLContext lwjglContext, CLContext clContext){
|
||||
this.lwjglContext = lwjglContext;
|
||||
pointer = CL30.clCreateCommandQueue(clContext.getPointer(), clContext.getDevice().getId(), MemoryUtil.NULL, clContext.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for this command queue
|
||||
* @return The pointer as a long
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queues a 2d kernel to work
|
||||
* @param kernel The kernel
|
||||
* @param waitList The list of events to wait on
|
||||
* @param workersInEachDimension The workers in each dimension of the data
|
||||
* @param workersInEachGroup The workers in each group of workers
|
||||
* @return The event representing this queued work
|
||||
*/
|
||||
public CLEvent queueKernelWork(
|
||||
CLKernel kernel,
|
||||
List<CLEvent> waitList,
|
||||
Vector2i workersInEachDimension,
|
||||
Vector2i workersInEachGroup
|
||||
){
|
||||
long[] dimensionArray = new long[]{
|
||||
workersInEachDimension.x,
|
||||
workersInEachDimension.y
|
||||
};
|
||||
long[] groupArray = new long[]{
|
||||
workersInEachGroup.x,
|
||||
workersInEachGroup.y
|
||||
};
|
||||
//dimensionality must be 2 as the work arrays are 2D vectors
|
||||
CLEvent event = queueKernelWork(kernel,waitList,2,dimensionArray,groupArray);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues kernel work with a default worker offset vector
|
||||
* @param kernel The kernel to queue work on
|
||||
* @param waitList The waitlist of events to wait for before executing this work
|
||||
* @param workDimensions The dimensionality of the data to act upon
|
||||
* @param workersInEachDimension The total number of workers in each dimension
|
||||
* @param workersInEachGroup The total number of workers in each work group
|
||||
* @return The opencl event for this work item
|
||||
*/
|
||||
public CLEvent queueKernelWork(
|
||||
CLKernel kernel,
|
||||
List<CLEvent> waitList,
|
||||
int workDimensions,
|
||||
long[] workersInEachDimension,
|
||||
long[] workersInEachGroup
|
||||
){
|
||||
return queueKernelWork(kernel, waitList, workDimensions, null, workersInEachDimension, workersInEachGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues work on a given opencl kernel
|
||||
* @param kernel The kernel to queue work on
|
||||
* @param waitList The waitlist of events to wait for before executing this work
|
||||
* @param workDimensions The dimensionality of the data to act upon
|
||||
* @param globalWorkerOffsetVector The vector specifying the amount of offset per dimension between given global workers
|
||||
* @param workersInEachDimension The total number of workers in each dimension
|
||||
* @param workersInEachGroup The total number of workers in each work group
|
||||
* @return The opencl event for this work item
|
||||
*/
|
||||
public CLEvent queueKernelWork(
|
||||
CLKernel kernel,
|
||||
List<CLEvent> waitList,
|
||||
int workDimensions,
|
||||
long[] globalWorkerOffsetVector, //basically a vector that describes the increment in each dimension. Unlikely to see use generally
|
||||
long[] workersInEachDimension, //basically the number of sub arrays
|
||||
long[] workersInEachGroup // basically the size of each subarray to work one
|
||||
){
|
||||
CLEvent rVal = null;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
//
|
||||
//construct and fill buffers for opencl call
|
||||
|
||||
//global worker offsets
|
||||
PointerBuffer globalWorkerOffset = null;
|
||||
if(globalWorkerOffsetVector != null){
|
||||
globalWorkerOffset = stack.mallocPointer(workDimensions);
|
||||
globalWorkerOffset.put(globalWorkerOffsetVector);
|
||||
globalWorkerOffset.flip();
|
||||
}
|
||||
|
||||
//global worker size
|
||||
PointerBuffer globalWorkerSize = null;
|
||||
globalWorkerSize = stack.mallocPointer(workDimensions);
|
||||
globalWorkerSize.put(workersInEachDimension);
|
||||
globalWorkerSize.flip();
|
||||
|
||||
//local worker size
|
||||
PointerBuffer localWorkerSize = stack.mallocPointer(workDimensions);
|
||||
localWorkerSize.put(workersInEachGroup);
|
||||
localWorkerSize.flip();
|
||||
|
||||
//the events to wait for before executing this one
|
||||
PointerBuffer eventWaitList = null;
|
||||
if(waitList != null && waitList.size() > 0){
|
||||
eventWaitList = stack.mallocPointer(waitList.size());
|
||||
for(CLEvent toWaitEvent : waitList){
|
||||
eventWaitList.put(toWaitEvent.getPointer());
|
||||
}
|
||||
}
|
||||
PointerBuffer event = stack.mallocPointer(1);
|
||||
|
||||
//
|
||||
//queue work
|
||||
CL30.clEnqueueNDRangeKernel(
|
||||
this.pointer,
|
||||
kernel.getPointer(),
|
||||
workDimensions,
|
||||
globalWorkerOffset,
|
||||
globalWorkerSize,
|
||||
localWorkerSize,
|
||||
eventWaitList,
|
||||
event
|
||||
);
|
||||
|
||||
//create returned event
|
||||
rVal = new CLEvent(event.get());
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an argument for a given kernel
|
||||
* @param kernel The kernel
|
||||
* @param argumentIndex The index of the argument (0-index'd)
|
||||
* @param argumentValue The value to set the argument to
|
||||
* @return The result of the argument set operation
|
||||
*/
|
||||
public int setKernelArgument(CLKernel kernel, int argumentIndex, long argumentValue){
|
||||
return CL30.clSetKernelArg(kernel.getPointer(),argumentIndex,argumentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an argument for a given kernel to be equal to a given image
|
||||
* @param kernel The kernel
|
||||
* @param argumentIndex The index of the argument (0-index'd)
|
||||
* @param image The value to set the argument to
|
||||
* @return The result of the argument set operation
|
||||
*/
|
||||
public int setKernelArgument(CLKernel kernel, int argumentIndex, CLImage image){
|
||||
int rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
PointerBuffer pointerBuffer = stack.mallocPointer(1);
|
||||
pointerBuffer.put(image.getPointer());
|
||||
pointerBuffer.flip();
|
||||
rVal = CL30.clSetKernelArg(kernel.getPointer(),argumentIndex,pointerBuffer);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an image from opencl global memory
|
||||
* @param image The image
|
||||
* @param waitList The wait list of events to make this query pend on
|
||||
* @return The byte buffer containing the data of the image
|
||||
*/
|
||||
public CLReadImageResult readImage(CLImage image, List<CLEvent> waitList){
|
||||
CLReadImageResult rVal = null;
|
||||
|
||||
//the cpu buffer to write into from gpu memory
|
||||
int bufferSize = (int)(image.getWidth() * image.getByteWidth());
|
||||
if(image.getHeight() > 0){
|
||||
bufferSize = (int)(bufferSize * image.getHeight());
|
||||
}
|
||||
if(image.getDepth() > 0){
|
||||
bufferSize = (int)(bufferSize * image.getDepth());
|
||||
}
|
||||
ByteBuffer outputBuffer = MemoryUtil.memAlloc(bufferSize);
|
||||
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
boolean blocking = false; //should the call block execution until the image is read?
|
||||
|
||||
//defines the offset in outputBuffer to start writing (should be a vec)
|
||||
PointerBuffer origin = stack.mallocPointer(3);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.flip();
|
||||
|
||||
//The dimensions of the image
|
||||
PointerBuffer region = stack.mallocPointer(3);
|
||||
region.put(image.getWidth());
|
||||
if(image.getHeight() == 0){
|
||||
region.put(1); //If it's a 1D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getHeight());
|
||||
}
|
||||
if(image.getDepth() == 0){
|
||||
region.put(1); //If it's a 2D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getDepth());
|
||||
}
|
||||
region.flip();
|
||||
|
||||
//how many bytes make up 1 line of the data
|
||||
long rowPitch = image.getByteWidth() * image.getWidth();
|
||||
|
||||
//how many bytes make up a single 2d plane of pixels. Should be 0 if image is 1d or 2d
|
||||
long slicePitch = 0;
|
||||
if(image.getDepth() > 0){
|
||||
slicePitch = image.getByteWidth() * image.getWidth() * image.getHeight();
|
||||
}
|
||||
|
||||
|
||||
//the event management buffers
|
||||
PointerBuffer eventWaitList = null;
|
||||
if(waitList != null && waitList.size() > 0){
|
||||
eventWaitList = stack.mallocPointer(waitList.size());
|
||||
for(CLEvent toWaitEvent : waitList){
|
||||
eventWaitList.put(toWaitEvent.getPointer());
|
||||
}
|
||||
eventWaitList.flip();
|
||||
}
|
||||
PointerBuffer event = stack.mallocPointer(1);
|
||||
|
||||
//actually send to opencl
|
||||
int errorCode = CL30.clEnqueueReadImage(
|
||||
this.getPointer(),
|
||||
image.getPointer(),
|
||||
blocking,
|
||||
origin,
|
||||
region,
|
||||
rowPitch,
|
||||
slicePitch,
|
||||
outputBuffer,
|
||||
eventWaitList,
|
||||
event
|
||||
);
|
||||
|
||||
//error check
|
||||
CLUtilities.checkCLError(errorCode);
|
||||
|
||||
//construct return object
|
||||
CLEvent returnEvent = new CLEvent(event.get());
|
||||
rVal = new CLReadImageResult(outputBuffer,returnEvent);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes to a device-side image in opencl
|
||||
* @param image The image to write to
|
||||
* @param data The data to write
|
||||
* @param waitList The waitlist of events to pend this write operation on
|
||||
* @return The CLEvent encapsulating this write operation
|
||||
*/
|
||||
public CLEvent writeToDeviceImage(CLImage image, List<CLEvent> waitList, int[] data){
|
||||
CLEvent rVal = null;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
boolean blocking = true;
|
||||
|
||||
//defines the offset in outputBuffer to start writing (should be a vec)
|
||||
PointerBuffer origin = stack.mallocPointer(3);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.flip();
|
||||
|
||||
//The dimensions of the image
|
||||
PointerBuffer region = stack.mallocPointer(3);
|
||||
region.put(image.getWidth());
|
||||
if(image.getHeight() == 0){
|
||||
region.put(1); //If it's a 1D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getHeight());
|
||||
}
|
||||
if(image.getDepth() == 0){
|
||||
region.put(1); //If it's a 2D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getDepth());
|
||||
}
|
||||
region.flip();
|
||||
|
||||
//how many bytes make up 1 line of the data
|
||||
long rowPitch = image.getByteWidth() * image.getWidth();
|
||||
|
||||
//how many bytes make up a single 2d plane of pixels. Should be 0 if image is 1d or 2d
|
||||
long slicePitch = 0;
|
||||
if(image.getDepth() > 0){
|
||||
slicePitch = image.getByteWidth() * image.getWidth() * image.getHeight();
|
||||
}
|
||||
|
||||
//the event management buffers
|
||||
PointerBuffer eventWaitList = null;
|
||||
if(waitList != null && waitList.size() > 0){
|
||||
eventWaitList = stack.mallocPointer(waitList.size());
|
||||
for(CLEvent toWaitEvent : waitList){
|
||||
eventWaitList.put(toWaitEvent.getPointer());
|
||||
}
|
||||
eventWaitList.flip();
|
||||
}
|
||||
PointerBuffer event = stack.mallocPointer(1);
|
||||
|
||||
int errorCode = CL30.clEnqueueWriteImage(this.getPointer(), image.getPointer(), blocking, origin, region, rowPitch, slicePitch, data, eventWaitList, event);
|
||||
|
||||
//error check
|
||||
CLUtilities.checkCLError(errorCode);
|
||||
|
||||
//construct return event
|
||||
rVal = new CLEvent(event.get());
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a buffer of bytes to a device-side image in opencl
|
||||
* @param image The image to write to
|
||||
* @param data The data to write
|
||||
* @param waitList The waitlist of events to pend this write operation on
|
||||
* @return The CLEvent encapsulating this write operation
|
||||
*/
|
||||
public CLEvent writeToDeviceImage(CLImage image, List<CLEvent> waitList, ByteBuffer data){
|
||||
CLEvent rVal = null;
|
||||
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
boolean blocking = false;
|
||||
|
||||
//defines the offset in outputBuffer to start writing (should be a vec)
|
||||
PointerBuffer origin = stack.mallocPointer(3);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.put(0);
|
||||
origin.flip();
|
||||
|
||||
//The dimensions of the image
|
||||
PointerBuffer region = stack.mallocPointer(3);
|
||||
region.put(image.getWidth());
|
||||
if(image.getHeight() == 0){
|
||||
region.put(1); //If it's a 1D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getHeight());
|
||||
}
|
||||
if(image.getDepth() == 0){
|
||||
region.put(1); //If it's a 2D image, this should be set to 1
|
||||
} else {
|
||||
region.put(image.getDepth());
|
||||
}
|
||||
region.flip();
|
||||
|
||||
//how many bytes make up 1 line of the data
|
||||
long rowPitch = image.getByteWidth() * image.getWidth();
|
||||
|
||||
//how many bytes make up a single 2d plane of pixels. Should be 0 if image is 1d or 2d
|
||||
long slicePitch = 0;
|
||||
if(image.getDepth() > 0){
|
||||
slicePitch = image.getByteWidth() * image.getWidth() * image.getHeight();
|
||||
}
|
||||
|
||||
//the event management buffers
|
||||
PointerBuffer eventWaitList = null;
|
||||
if(waitList != null && waitList.size() > 0){
|
||||
eventWaitList = stack.mallocPointer(waitList.size());
|
||||
for(CLEvent toWaitEvent : waitList){
|
||||
eventWaitList.put(toWaitEvent.getPointer());
|
||||
}
|
||||
eventWaitList.flip();
|
||||
}
|
||||
PointerBuffer event = stack.mallocPointer(1);
|
||||
|
||||
int errorCode = CL30.clEnqueueWriteImage(this.getPointer(), image.getPointer(), blocking, origin, region, rowPitch, slicePitch, data, eventWaitList, event);
|
||||
|
||||
//error check
|
||||
CLUtilities.checkCLError(errorCode);
|
||||
|
||||
//construct return event
|
||||
rVal = new CLEvent(event.get());
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks thread execution until the event list has completed or otherwise resolved
|
||||
* @param eventList The event list
|
||||
*/
|
||||
public void waitForEventList(List<CLEvent> waitList){
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
PointerBuffer eventWaitList = null;
|
||||
if(waitList != null && waitList.size() > 0){
|
||||
eventWaitList = stack.mallocPointer(waitList.size());
|
||||
for(CLEvent toWaitEvent : waitList){
|
||||
eventWaitList.put(toWaitEvent.getPointer());
|
||||
}
|
||||
eventWaitList.flip();
|
||||
}
|
||||
|
||||
//wait
|
||||
int errorCode = CL30.clWaitForEvents(eventWaitList);
|
||||
|
||||
//error check
|
||||
CLUtilities.checkCLError(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,164 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.opencl.CLContextCallback;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl context
|
||||
*/
|
||||
public class CLContext {
|
||||
|
||||
//the context pointer
|
||||
long pointer;
|
||||
|
||||
//the context callback
|
||||
CLContextCallback clContextCB;
|
||||
//the error code buffer
|
||||
IntBuffer errorCodeBuffer = BufferUtils.createIntBuffer(1);
|
||||
int[] errorCodeArray = new int[1];
|
||||
|
||||
//the device this context is created on
|
||||
CLDevice device;
|
||||
|
||||
//creates an opencl context
|
||||
public CLContext(CLDevice device, PointerBuffer ctxProps){
|
||||
pointer = CL30.clCreateContext(ctxProps, device.getId(), clContextCB = CLContextCallback.create(
|
||||
(errinfo, private_info, cb, user_data) -> System.out.println(String.format("clCreateContext\n\tInfo: %s", MemoryUtil.memUTF8(errinfo)))
|
||||
), MemoryUtil.NULL, errorCodeBuffer);
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for this context
|
||||
* @return The pointer
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the opencl error code storage buffer
|
||||
* @return The opencl error code storage buffer
|
||||
*/
|
||||
protected IntBuffer getErrorCodeBuffer(){
|
||||
return errorCodeBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array used for storing error codes in relevant api calls
|
||||
* @return The array
|
||||
*/
|
||||
protected int[] getErrorCodeArray(){
|
||||
return errorCodeArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an opencl buffer with a specified size
|
||||
* @param flags The flags for the buffer
|
||||
* @param size The size of the opencl buffer in bytes
|
||||
* @return The opencl buffer
|
||||
*/
|
||||
public CLBuffer createBuffer(long flags, long size){
|
||||
CLBuffer buffer = new CLBuffer(this, flags, size);
|
||||
CLUtilities.checkCLError(errorCodeBuffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an opencl buffer based on a cpu buffer
|
||||
* @param flags The flags for the buffer
|
||||
* @param hostBuffer The cpu buffer to base the opencl buffer on
|
||||
* @return The opencl buffer
|
||||
*/
|
||||
public CLBuffer createBuffer(long flags, IntBuffer hostBuffer){
|
||||
CLBuffer buffer = new CLBuffer(this, flags, hostBuffer);
|
||||
CLUtilities.checkCLError(errorCodeBuffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 2d opencl image buffer
|
||||
* @param flags The flags for creation of the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @return The opencl image wrapper object
|
||||
*/
|
||||
public CLImage createImage(long flags, long width, long height){
|
||||
CLImage image = new CLImage(this, flags, width, height);
|
||||
CLUtilities.checkCLError(errorCodeBuffer);
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 3d opencl image buffer
|
||||
* @param flags The flags for creation of the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @param depth The depth of the image
|
||||
* @return The opencl image wrapper object
|
||||
*/
|
||||
public CLImage createImage(long flags, long width, long height, long depth){
|
||||
CLImage image = new CLImage(this, flags, width, height, depth);
|
||||
CLUtilities.checkCLError(errorCodeBuffer);
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 3d opencl image buffer
|
||||
* @param flags The flags for creation of the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @param depth The depth of the image
|
||||
* @param data The data to init the image with
|
||||
* @return The opencl image wrapper object
|
||||
*/
|
||||
public CLImage createImage(long flags, long width, long height, long depth, ByteBuffer data){
|
||||
CLImage image = new CLImage(this, flags, width, height, depth, data);
|
||||
CLUtilities.checkCLError(errorCodeBuffer);
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command queue for this context
|
||||
* @return The command queue
|
||||
*/
|
||||
public CLCommandQueue createCommandQueue(LWJGLContext lwjglContext){
|
||||
return new CLCommandQueue(lwjglContext, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the opencl device this context was created on
|
||||
* @return The device
|
||||
*/
|
||||
public CLDevice getDevice(){
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an opencl program with a provided source
|
||||
* @param source The source
|
||||
* @return The program
|
||||
*/
|
||||
public CLProgram createProgram(String source){
|
||||
CLProgram program = CLProgram.createProgram(this, source);
|
||||
return program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an opencl kernel from the specified program
|
||||
* @param program The program
|
||||
* @param kernelName The name of the kernel in the program source
|
||||
* @return The kernel object
|
||||
*/
|
||||
public CLKernel createKernel(CLProgram program, String kernelName){
|
||||
CLKernel kernel = new CLKernel(this, program, kernelName);
|
||||
return kernel;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import org.lwjgl.opencl.CL30;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl device
|
||||
*/
|
||||
public class CLDevice {
|
||||
|
||||
//the id of the device
|
||||
long id;
|
||||
|
||||
//the name of the device
|
||||
String deviceName;
|
||||
|
||||
//true if the device is a gpu
|
||||
boolean isGpu = false;
|
||||
|
||||
//true if the device is available
|
||||
boolean isAvailable = false;
|
||||
|
||||
/**
|
||||
* Creates a CL device wrapper object
|
||||
* @param id the id of the device
|
||||
* @param isGpu true if the device is a gpu
|
||||
*/
|
||||
protected CLDevice(long id){
|
||||
this.id = id;
|
||||
//get device name
|
||||
deviceName = CLUtilities.getDeviceInfoStringUTF8(id, CL30.CL_DEVICE_NAME);
|
||||
//get if device is gpu
|
||||
long deviceType = CLUtilities.getDeviceInfoLong(id, CL30.CL_DEVICE_TYPE);
|
||||
if (deviceType == CL30.CL_DEVICE_TYPE_GPU) {
|
||||
isGpu = true;
|
||||
}
|
||||
//check if is available
|
||||
long isAvailableRaw = CLUtilities.getDeviceInfoLong(id, CL30.CL_DEVICE_AVAILABLE);
|
||||
if(isAvailableRaw == CL30.CL_TRUE){
|
||||
isAvailable = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the device
|
||||
* @return the id of the device
|
||||
*/
|
||||
public long getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the device is a gpu
|
||||
* @return True if the device is a gpu
|
||||
*/
|
||||
public boolean isGpu(){
|
||||
return isGpu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the device
|
||||
* @return The name of the device
|
||||
*/
|
||||
public String getDeviceName(){
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Wrapper for an opencl event
|
||||
*/
|
||||
public class CLEvent {
|
||||
|
||||
//The pointer for the event
|
||||
long pointer;
|
||||
|
||||
/**
|
||||
* Constructs a wrapper object around an opencl event
|
||||
* @param pointer The pointer for the event
|
||||
*/
|
||||
protected CLEvent(long pointer){
|
||||
this.pointer = pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for this event
|
||||
* @return The pointer as a long
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queries the status of the event from opencl
|
||||
* @return The event status code
|
||||
*/
|
||||
public int getStatus(){
|
||||
int rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
//create buffers for call
|
||||
ByteBuffer returnValueBuffer = stack.malloc(1);
|
||||
PointerBuffer sizeBuffer = stack.mallocPointer(1);
|
||||
|
||||
//submit request to opencl
|
||||
int errorCode = CL30.clGetEventInfo(this.getPointer(),CL30.CL_EVENT_COMMAND_EXECUTION_STATUS,returnValueBuffer,sizeBuffer);
|
||||
|
||||
//check error
|
||||
CLUtilities.checkCLError(errorCode);
|
||||
|
||||
//get return value
|
||||
rVal = returnValueBuffer.getInt();
|
||||
|
||||
// //free buffers
|
||||
// MemoryUtil.memFree(returnValueBuffer);
|
||||
// sizeBuffer.free();
|
||||
}
|
||||
|
||||
//return
|
||||
return rVal;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,218 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.opencl.CLImageDesc;
|
||||
import org.lwjgl.opencl.CLImageFormat;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl image
|
||||
*/
|
||||
public class CLImage {
|
||||
|
||||
//the pointer to the image
|
||||
long pointer;
|
||||
|
||||
//The dimensions of the image
|
||||
long width;
|
||||
long height;
|
||||
long depth;
|
||||
|
||||
//true if device can read from the image
|
||||
boolean canRead;
|
||||
//true if device can write to the image
|
||||
boolean canWrite;
|
||||
|
||||
//the number of bytes per pixel. This is used by the command queue fetching tasks to allocate buffer sizes
|
||||
long byteWidth;
|
||||
|
||||
/**
|
||||
* Creates an empty 2d image
|
||||
* @param context The context to create the image in
|
||||
* @param flags The flags for the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
*/
|
||||
protected CLImage(CLContext context, long flags, long width, long height){
|
||||
//set initial values
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.depth = 0;
|
||||
|
||||
//parse flags
|
||||
this.parseFlags(flags);
|
||||
|
||||
//
|
||||
//Get the image format
|
||||
CLImageFormat imageFormat = CLImageFormat.create();
|
||||
imageFormat.image_channel_data_type(CL30.CL_SNORM_INT8);
|
||||
byteWidth = 4;
|
||||
imageFormat.image_channel_order(CL30.CL_RGBA);
|
||||
|
||||
//
|
||||
//Get the image description
|
||||
CLImageDesc imageDesc = CLImageDesc.create();
|
||||
imageDesc.image_type(CL30.CL_MEM_OBJECT_IMAGE2D);
|
||||
imageDesc.image_width(width);
|
||||
imageDesc.image_height(height);
|
||||
imageDesc.image_depth(0); //only used for 3d image
|
||||
imageDesc.image_array_size(1); //only used for 1d and 2d images
|
||||
imageDesc.image_row_pitch(0); //must be 0 if host ptr is null
|
||||
imageDesc.image_slice_pitch(0); //must be 0 if host ptr is null
|
||||
|
||||
//
|
||||
//host pointer (the data to prepopulate with)
|
||||
IntBuffer hostPointerBuffer = null; //BufferUtils.createIntBuffer(1);
|
||||
|
||||
//
|
||||
//Create the image object
|
||||
pointer = CL30.clCreateImage(context.getPointer(), flags, imageFormat, imageDesc, hostPointerBuffer, context.getErrorCodeBuffer());
|
||||
|
||||
//error check
|
||||
CLUtilities.checkCLError(context.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty 3d image
|
||||
* @param context The context to create the image in
|
||||
* @param flags The flags for the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @param depth The depth of the image
|
||||
*/
|
||||
protected CLImage(CLContext context, long flags, long width, long height, long depth){
|
||||
//set initial values
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.depth = depth;
|
||||
|
||||
//parse flags
|
||||
this.parseFlags(flags);
|
||||
|
||||
//
|
||||
//Get the image format
|
||||
CLImageFormat imageFormat = CLImageFormat.create();
|
||||
imageFormat.image_channel_data_type(CL30.CL_SNORM_INT8);
|
||||
byteWidth = 4;
|
||||
imageFormat.image_channel_order(CL30.CL_RGBA);
|
||||
|
||||
//
|
||||
//Get the image description
|
||||
CLImageDesc imageDesc = CLImageDesc.create();
|
||||
imageDesc.image_type(CL30.CL_MEM_OBJECT_IMAGE3D);
|
||||
imageDesc.image_width(width);
|
||||
imageDesc.image_height(height);
|
||||
imageDesc.image_depth(depth); //only used for 3d image
|
||||
imageDesc.image_array_size(1); //only used for 1d and 2d images
|
||||
imageDesc.image_row_pitch(0); //must be 0 if host ptr is null
|
||||
imageDesc.image_slice_pitch(0); //must be 0 if host ptr is null
|
||||
|
||||
//
|
||||
//host pointer (the data to prepopulate with)
|
||||
IntBuffer hostPointerBuffer = null; //BufferUtils.createIntBuffer(1);
|
||||
|
||||
//
|
||||
//Create the image object
|
||||
pointer = CL30.clCreateImage(context.getPointer(), flags, imageFormat, imageDesc, hostPointerBuffer, context.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty 3d image
|
||||
* @param context The context to create the image in
|
||||
* @param flags The flags for the image
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @param depth The depth of the image
|
||||
*/
|
||||
protected CLImage(CLContext context, long flags, long width, long height, long depth, ByteBuffer data){
|
||||
//set initial values
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.depth = depth;
|
||||
|
||||
//parse flags
|
||||
this.parseFlags(flags);
|
||||
|
||||
//
|
||||
//Get the image format
|
||||
CLImageFormat imageFormat = CLImageFormat.create();
|
||||
imageFormat.image_channel_data_type(CL30.CL_SNORM_INT8);
|
||||
byteWidth = 4;
|
||||
imageFormat.image_channel_order(CL30.CL_RGBA);
|
||||
|
||||
//
|
||||
//Get the image description
|
||||
CLImageDesc imageDesc = CLImageDesc.create();
|
||||
imageDesc.image_type(CL30.CL_MEM_OBJECT_IMAGE3D);
|
||||
imageDesc.image_width(width);
|
||||
imageDesc.image_height(height);
|
||||
imageDesc.image_depth(depth); //only used for 3d image
|
||||
imageDesc.image_array_size(1); //only used for 1d and 2d images
|
||||
imageDesc.image_row_pitch(width * byteWidth); //must be 0 if host ptr is null
|
||||
imageDesc.image_slice_pitch(width * height * byteWidth); //must be 0 if host ptr is null
|
||||
|
||||
//
|
||||
//Create the image object
|
||||
pointer = CL30.clCreateImage(context.getPointer(), flags, imageFormat, imageDesc, data, context.getErrorCodeBuffer());
|
||||
|
||||
CLUtilities.checkCLError(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the flags passed in on image creation to set variables (eg read/write status)
|
||||
* @param flags The flags passed in
|
||||
*/
|
||||
private void parseFlags(long flags){
|
||||
if((CL30.CL_MEM_READ_ONLY & flags) != 0){
|
||||
this.canRead = true;
|
||||
}
|
||||
if((CL30.CL_MEM_WRITE_ONLY & flags) != 0){
|
||||
this.canWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for the image
|
||||
* @return The image pointer
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of the image
|
||||
* @return The width of the image
|
||||
*/
|
||||
public long getWidth(){
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of the image
|
||||
* @return The height of the image
|
||||
*/
|
||||
public long getHeight(){
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the depth of the image
|
||||
* @return The depth of the image
|
||||
*/
|
||||
public long getDepth(){
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the byte width of the image
|
||||
* @return The byte width
|
||||
*/
|
||||
public long getByteWidth(){
|
||||
return byteWidth;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import org.lwjgl.opencl.CL30;
|
||||
|
||||
/**
|
||||
* A wrapper object for an opencl kernel
|
||||
*/
|
||||
public class CLKernel {
|
||||
|
||||
//The pointer to the kernel
|
||||
long pointer;
|
||||
|
||||
/**
|
||||
* Creates a cl kernel from a context and a program
|
||||
* @param context The opencl context
|
||||
* @param program The opencl program
|
||||
* @param kernelName The name of the kernel
|
||||
*/
|
||||
protected CLKernel(CLContext context, CLProgram program, String kernelName){
|
||||
pointer = CL30.clCreateKernel(program.getPointer(), kernelName, context.getErrorCodeBuffer());
|
||||
CLUtilities.checkCLError(context.getErrorCodeBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for this kernel
|
||||
* @return The pointer as a long
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,153 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.opencl.CLCapabilities;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
/**
|
||||
* An object that encapsulates an openCL platform
|
||||
*/
|
||||
public class CLPlatform {
|
||||
|
||||
//the id of the platform
|
||||
long id;
|
||||
|
||||
//the capabilities of the platform
|
||||
CLCapabilities caps;
|
||||
|
||||
//Information about the platform
|
||||
String vendor;
|
||||
String name;
|
||||
String version;
|
||||
|
||||
// the list of all cl devices on this platform
|
||||
List<CLDevice> clDevices;
|
||||
|
||||
/**
|
||||
* Creates a platform object
|
||||
* @param id The id of the platform
|
||||
*/
|
||||
protected CLPlatform(long id, CLCapabilities caps, String vendor, String name, String version, List<CLDevice> clDevices){
|
||||
this.id = id;
|
||||
this.caps = caps;
|
||||
this.vendor = vendor;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.clDevices = clDevices;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a set containing all currently available platforms
|
||||
* @return The set containing all currently available platforms
|
||||
*/
|
||||
public static Set<CLPlatform> getPlatforms(){
|
||||
Set<CLPlatform> platforms = new HashSet<CLPlatform>();
|
||||
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
//check if there are any platforms
|
||||
IntBuffer pi = stack.mallocInt(1);
|
||||
CLUtilities.checkCLError(CL30.clGetPlatformIDs(null, pi));
|
||||
if (pi.get(0) == 0) {
|
||||
throw new IllegalStateException("No OpenCL platforms found.");
|
||||
}
|
||||
//if there are platforms, get all platform IDs
|
||||
PointerBuffer platformIDs = stack.mallocPointer(pi.get(0));
|
||||
CLUtilities.checkCLError(CL30.clGetPlatformIDs(platformIDs, (IntBuffer)null));
|
||||
|
||||
//add all platforms to the returned list
|
||||
for (int i = 0; i < platformIDs.capacity(); i++) {
|
||||
//get basic identification
|
||||
long platformId = platformIDs.get(i);
|
||||
CLCapabilities caps = CL.createPlatformCapabilities(platformId);
|
||||
String vendor = CLUtilities.getPlatformInfoStringUTF8(platformId, CL30.CL_PLATFORM_VENDOR);
|
||||
String name = CLUtilities.getPlatformInfoStringUTF8(platformId, CL30.CL_PLATFORM_NAME);
|
||||
String version = CLUtilities.getPlatformInfoStringUTF8(platformId, CL30.CL_PLATFORM_VERSION);
|
||||
|
||||
|
||||
//get devices on the platform
|
||||
int errcode = CL30.clGetDeviceIDs(platformId, CL30.CL_DEVICE_TYPE_GPU, null, pi);
|
||||
List<CLDevice> devices = new LinkedList<CLDevice>();
|
||||
if(errcode != CL30.CL_DEVICE_NOT_FOUND){
|
||||
CLUtilities.checkCLError(errcode);
|
||||
PointerBuffer deviceIDs = stack.mallocPointer(pi.get(0));
|
||||
CLUtilities.checkCLError(CL30.clGetDeviceIDs(platformId, CL30.CL_DEVICE_TYPE_ALL, deviceIDs, (IntBuffer)null));
|
||||
for (int j = 0; j < deviceIDs.capacity(); j++) {
|
||||
long deviceId = deviceIDs.get(j);
|
||||
devices.add(new CLDevice(deviceId));
|
||||
}
|
||||
}
|
||||
|
||||
platforms.add(new CLPlatform(platformId, caps, vendor, name, version, devices));
|
||||
}
|
||||
|
||||
if (platforms.isEmpty()) {
|
||||
throw new IllegalStateException("No OpenCL platform found.");
|
||||
}
|
||||
}
|
||||
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the platform
|
||||
* @return the id of the platfomr
|
||||
*/
|
||||
public long getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the capabilities object of the platform
|
||||
* @return The capabilities
|
||||
*/
|
||||
public CLCapabilities getCapabilities(){
|
||||
return caps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the vendor the platform
|
||||
* @return The name of the vendor of the platform
|
||||
*/
|
||||
public String getVendor(){
|
||||
return vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the platform
|
||||
* @return The name of the platform
|
||||
*/
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of opencl on the platform
|
||||
* @return The version of opencl on the platform
|
||||
*/
|
||||
public String getVersion(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of cl devices on this platform
|
||||
* @return The list of devices
|
||||
*/
|
||||
public List<CLDevice> getCLDevices(){
|
||||
return clDevices;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.opencl.CLProgramCallback;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* Wrapper object for an opencl program
|
||||
*/
|
||||
public class CLProgram {
|
||||
|
||||
//the pointer to the program
|
||||
long pointer;
|
||||
|
||||
/**
|
||||
* Creates an opencl program from a context and a source
|
||||
* @param context The context
|
||||
* @param source The source
|
||||
* @return The program
|
||||
*/
|
||||
protected static CLProgram createProgram(CLContext context, String source){
|
||||
CLProgram program = new CLProgram();
|
||||
|
||||
//create object
|
||||
program.pointer = CL30.clCreateProgramWithSource(context.getPointer(), source, context.getErrorCodeBuffer());
|
||||
CLUtilities.checkCLError(context.getErrorCodeBuffer());
|
||||
|
||||
//latch for blocking execution until the program finishes compiling
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
//build the program
|
||||
String options = "";
|
||||
CLProgramCallback buildCallback;
|
||||
int errcode = CL30.clBuildProgram(program.pointer, context.getDevice().getId(), options, buildCallback = CLProgramCallback.create((programId, user_data) -> {
|
||||
System.out.println(String.format(
|
||||
"The cl_program [0x%X] was built %s",
|
||||
programId,
|
||||
CLUtilities.getProgramBuildInfoInt(programId, context.getDevice().getId(), CL30.CL_PROGRAM_BUILD_STATUS) == CL30.CL_SUCCESS ? "successfully" : "unsuccessfully"
|
||||
));
|
||||
String log = CLUtilities.getProgramBuildInfoStringASCII(programId, context.getDevice().getId(), CL30.CL_PROGRAM_BUILD_LOG);
|
||||
if (!log.isEmpty()) {
|
||||
System.out.println(String.format("BUILD LOG:\n----\n%s\n-----", log));
|
||||
}
|
||||
|
||||
latch.countDown();
|
||||
}), MemoryUtil.NULL);
|
||||
CLUtilities.checkCLError(errcode);
|
||||
|
||||
//Block execution until the program finishes building
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
buildCallback.free();
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pointer for this program object
|
||||
* @return The pointer as a long
|
||||
*/
|
||||
public long getPointer(){
|
||||
return pointer;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A pair of an opencl event and the buffer from the read operation. Used so we can pass back both from the call.
|
||||
*/
|
||||
public class CLReadImageResult {
|
||||
|
||||
//the buffer
|
||||
ByteBuffer buffer;
|
||||
//the event
|
||||
CLEvent event;
|
||||
|
||||
/**
|
||||
* Constructs the pair
|
||||
* @param buffer The buffer
|
||||
* @param event The event
|
||||
*/
|
||||
protected CLReadImageResult(ByteBuffer buffer, CLEvent event){
|
||||
this.buffer = buffer;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer
|
||||
* @return The buffer
|
||||
*/
|
||||
public ByteBuffer getBuffer(){
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the event
|
||||
* @return The event
|
||||
*/
|
||||
public CLEvent getEvent(){
|
||||
return event;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,181 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opencl.CL30;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import static org.lwjgl.opencl.CL30.*;
|
||||
import static org.lwjgl.system.MemoryStack.*;
|
||||
import static org.lwjgl.system.MemoryUtil.*;
|
||||
|
||||
/**
|
||||
* Utilities for all opencl files (for instance error checking functions)
|
||||
*/
|
||||
public class CLUtilities {
|
||||
|
||||
/**
|
||||
* Checks an opencl error code
|
||||
* @param errcode The error code
|
||||
*/
|
||||
public static void checkCLError(IntBuffer errcode) {
|
||||
checkCLError(errcode.get(errcode.position()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks an opencl error code
|
||||
* @param errcode The error code
|
||||
*/
|
||||
public static void checkCLError(int errcode) {
|
||||
if (errcode != CL_SUCCESS) {
|
||||
throw new RuntimeException(String.format("OpenCL error [%d]", errcode));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks an opencl error code
|
||||
* @param context The context containing the error code buffer
|
||||
*/
|
||||
public static void checkCLError(CLContext context) {
|
||||
int code = context.getErrorCodeBuffer().get();
|
||||
if (code != CL_SUCCESS) {
|
||||
throw new RuntimeException(String.format("OpenCL error [%d]", code));
|
||||
}
|
||||
context.getErrorCodeBuffer().flip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a platform info as a utf string
|
||||
* @param platformId The platform id
|
||||
* @param paramName The parameter name
|
||||
* @return The string containing the information
|
||||
*/
|
||||
public static String getPlatformInfoStringUTF8(long platformId, int paramName) {
|
||||
String rVal = "";
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
PointerBuffer resultSizeBuffer = stack.mallocPointer(1);
|
||||
checkCLError(CL30.clGetPlatformInfo(platformId, paramName, (ByteBuffer)null, resultSizeBuffer));
|
||||
int bytes = (int)resultSizeBuffer.get(0);
|
||||
|
||||
ByteBuffer buffer = stack.malloc(bytes);
|
||||
checkCLError(CL30.clGetPlatformInfo(platformId, paramName, buffer, null));
|
||||
rVal = memUTF8(buffer, bytes - 1);
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an opencl device parameter as a utf8 string
|
||||
* @param deviceId The device id
|
||||
* @param paramName The parameter name
|
||||
* @return The string
|
||||
*/
|
||||
public static String getDeviceInfoStringUTF8(long deviceId, int paramName) {
|
||||
String rVal = "";
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
PointerBuffer pp = stack.mallocPointer(1);
|
||||
checkCLError(clGetDeviceInfo(deviceId, paramName, (ByteBuffer)null, pp));
|
||||
int bytes = (int)pp.get(0);
|
||||
|
||||
ByteBuffer buffer = stack.malloc(bytes);
|
||||
checkCLError(clGetDeviceInfo(deviceId, paramName, buffer, null));
|
||||
rVal = memUTF8(buffer, bytes - 1);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a device parameter's value as an int
|
||||
* @param deviceId The id of the device
|
||||
* @param paramName The parameter name
|
||||
* @return The int
|
||||
*/
|
||||
public static int getDeviceInfoInt(long deviceId, int paramName) {
|
||||
int rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
IntBuffer pl = stack.mallocInt(1);
|
||||
checkCLError(clGetDeviceInfo(deviceId, paramName, pl, null));
|
||||
rVal = pl.get(0);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a device's parameter's value as a long
|
||||
* @param deviceId The device's id
|
||||
* @param paramName The parameter name
|
||||
* @return The value as a long
|
||||
*/
|
||||
public static long getDeviceInfoLong(long deviceId, int paramName) {
|
||||
long rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
LongBuffer pl = stack.mallocLong(1);
|
||||
checkCLError(clGetDeviceInfo(deviceId, paramName, pl, null));
|
||||
rVal = pl.get(0);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a device's parameter's value as a boolean
|
||||
* @param deviceId The device's id
|
||||
* @param paramName The parameter name
|
||||
* @return The value as a boolean
|
||||
*/
|
||||
public static boolean getDeviceInfoBoolean(long deviceId, int paramName) {
|
||||
byte rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
ByteBuffer pl = stack.malloc(1);
|
||||
checkCLError(clGetDeviceInfo(deviceId, paramName, pl, null));
|
||||
rVal = pl.get(0);
|
||||
}
|
||||
return rVal == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an opencl program build parameter as an int
|
||||
* @param programId The program id
|
||||
* @param deviceId The device id
|
||||
* @param parameterName The parameter name
|
||||
* @return THe value of the parameter as an int
|
||||
*/
|
||||
public static int getProgramBuildInfoInt(long programId, long deviceId, int parameterName) {
|
||||
int rVal = 0;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
IntBuffer pl = stack.mallocInt(1);
|
||||
checkCLError(clGetProgramBuildInfo(programId, deviceId, parameterName, pl, null));
|
||||
rVal = pl.get(0);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an opencl program build parameter as a string
|
||||
* @param programId The program id
|
||||
* @param deviceId The device id
|
||||
* @param parameterName The parameter name
|
||||
* @return The value of the parameter as a string
|
||||
*/
|
||||
public static String getProgramBuildInfoStringASCII(long programId, long deviceId, int parameterName) {
|
||||
String rVal = "";
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
PointerBuffer pp = stack.mallocPointer(1);
|
||||
checkCLError(clGetProgramBuildInfo(programId, deviceId, parameterName, (ByteBuffer)null, pp));
|
||||
int bytes = (int)pp.get(0);
|
||||
|
||||
ByteBuffer buffer = stack.malloc(bytes);
|
||||
checkCLError(clGetProgramBuildInfo(programId, deviceId, parameterName, buffer, null));
|
||||
|
||||
rVal = memASCII(buffer, bytes - 1);;
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package electrosphere.opencl;
|
||||
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
/**
|
||||
* A context for the lwjgl framework. Contains stack used by opencl api.
|
||||
*/
|
||||
public class LWJGLContext {
|
||||
|
||||
//The stack for memory allocation
|
||||
MemoryStack stack;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public LWJGLContext(){
|
||||
stack = MemoryStack.create(1000 * 1000 * 4 * 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the memory stack for the current context
|
||||
* @return The lwjgl context's memory stack
|
||||
*/
|
||||
public MemoryStack getStack(){
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
@ -39,14 +39,19 @@ public class GLFWContext {
|
||||
//Maximize it
|
||||
GLFW.glfwMaximizeWindow(window);
|
||||
//grab actual framebuffer
|
||||
IntBuffer xBuffer = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer yBuffer = BufferUtils.createIntBuffer(1);
|
||||
GLFW.glfwGetFramebufferSize(window, xBuffer, yBuffer);
|
||||
MemoryUtil.memFree(xBuffer);
|
||||
MemoryUtil.memFree(yBuffer);
|
||||
|
||||
int bufferWidth = xBuffer.get();
|
||||
int bufferHeight = yBuffer.get();
|
||||
int bufferWidth = 0;
|
||||
int bufferHeight = 0;
|
||||
|
||||
try(MemoryStack stack = MemoryStack.stackPush()){
|
||||
IntBuffer xBuffer = MemoryUtil.memAllocInt(1);
|
||||
IntBuffer yBuffer = MemoryUtil.memAllocInt(1);
|
||||
GLFW.glfwGetFramebufferSize(window, xBuffer, yBuffer);
|
||||
MemoryUtil.memFree(xBuffer);
|
||||
MemoryUtil.memFree(yBuffer);
|
||||
|
||||
bufferWidth = xBuffer.get();
|
||||
bufferHeight = yBuffer.get();
|
||||
}
|
||||
|
||||
//
|
||||
// Attack controls callbacks
|
||||
|
||||
19
src/main/java/electrosphere/render/GridCell.java
Normal file
19
src/main/java/electrosphere/render/GridCell.java
Normal file
@ -0,0 +1,19 @@
|
||||
package electrosphere.render;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class GridCell {
|
||||
Vector3f[] points = new Vector3f[8]; //array of size 8
|
||||
double[] val = new double[8]; //array of size 8
|
||||
public void setValues(
|
||||
Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4,
|
||||
Vector3f p5, Vector3f p6, Vector3f p7, Vector3f p8,
|
||||
double val1, double val2, double val3, double val4,
|
||||
double val5, double val6, double val7, double val8
|
||||
){
|
||||
points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4;
|
||||
points[4] = p5; points[5] = p6; points[6] = p7; points[7] = p8;
|
||||
val[0] = val1; val[1] = val2; val[2] = val3; val[3] = val4;
|
||||
val[4] = val5; val[5] = val6; val[6] = val7; val[7] = val8;
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ public class Mesh {
|
||||
static Matrix4f projectionMatrix = new Matrix4f();
|
||||
static Matrix4f model = new Matrix4f().identity();
|
||||
|
||||
static MemoryStack stack = MemoryStack.create(16 * 1000 * 1000);
|
||||
static MemoryStack stack = MemoryStack.create(32 * 1000 * 1000);
|
||||
|
||||
public static void meshInitially(FluidSim sim){
|
||||
//create and bind vao
|
||||
@ -55,7 +55,7 @@ public class Mesh {
|
||||
GL44.glBindBuffer(GL44.GL_ARRAY_BUFFER, vertBufferPtr);
|
||||
try {
|
||||
int vertexCount = data.vertices.size();
|
||||
FloatBuffer vertData = BufferUtils.createFloatBuffer(vertexCount);
|
||||
FloatBuffer vertData = MemoryUtil.memAllocFloat(vertexCount);
|
||||
for(float vertValue : data.vertices){
|
||||
vertData.put(vertValue);
|
||||
}
|
||||
@ -63,7 +63,7 @@ public class Mesh {
|
||||
GL44.glBufferData(GL44.GL_ARRAY_BUFFER,vertData,GL44.GL_STATIC_DRAW);
|
||||
GL44.glVertexAttribPointer(0, 3, GL44.GL_FLOAT, false, 0, 0);
|
||||
GL44.glEnableVertexAttribArray(0);
|
||||
// MemoryUtil.memFree(vertData);
|
||||
MemoryUtil.memFree(vertData);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -77,13 +77,13 @@ public class Mesh {
|
||||
GL44.glBindBuffer(GL44.GL_ELEMENT_ARRAY_BUFFER, faceBufferPtr);
|
||||
elementCount = data.elements.size();
|
||||
try {
|
||||
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(elementCount);
|
||||
IntBuffer elementArrayBufferData = MemoryUtil.memAllocInt(elementCount);
|
||||
for(int element : data.elements){
|
||||
elementArrayBufferData.put(element);
|
||||
}
|
||||
elementArrayBufferData.flip();
|
||||
GL44.glBufferData(GL45.GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferData,GL44.GL_STATIC_DRAW);
|
||||
// MemoryUtil.memFree(elementArrayBufferData);
|
||||
MemoryUtil.memFree(elementArrayBufferData);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -100,7 +100,7 @@ public class Mesh {
|
||||
int normalCount = data.normals.size() / 3;
|
||||
FloatBuffer NormalArrayBufferData;
|
||||
if(normalCount > 0){
|
||||
NormalArrayBufferData = BufferUtils.createFloatBuffer(normalCount * 3);
|
||||
NormalArrayBufferData = MemoryUtil.memAllocFloat(normalCount * 3);
|
||||
float[] temp = new float[3];
|
||||
for(float normalValue : data.normals){
|
||||
NormalArrayBufferData.put(normalValue);
|
||||
@ -202,67 +202,66 @@ public class Mesh {
|
||||
//generate verts
|
||||
TerrainChunkData data = generateTerrainChunkData(sim.getData());
|
||||
|
||||
try(MemoryStack stackLocal = stack.push()){
|
||||
|
||||
//
|
||||
//Buffer data to GPU
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ARRAY_BUFFER, vertBufferPtr);
|
||||
try {
|
||||
int vertexCount = data.vertices.size();
|
||||
FloatBuffer vertData = stackLocal.mallocFloat(vertexCount);
|
||||
for(float vertValue : data.vertices){
|
||||
vertData.put(vertValue);
|
||||
}
|
||||
vertData.flip();
|
||||
GL44.glBufferData(GL44.GL_ARRAY_BUFFER,vertData,GL44.GL_STATIC_DRAW);
|
||||
GL44.glVertexAttribPointer(0, 3, GL44.GL_FLOAT, false, 0, 0);
|
||||
GL44.glEnableVertexAttribArray(0);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
//
|
||||
//Buffer data to GPU
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ARRAY_BUFFER, vertBufferPtr);
|
||||
try {
|
||||
int vertexCount = data.vertices.size();
|
||||
FloatBuffer vertData = MemoryUtil.memAllocFloat(vertexCount);
|
||||
for(float vertValue : data.vertices){
|
||||
vertData.put(vertValue);
|
||||
}
|
||||
|
||||
vertData.flip();
|
||||
GL44.glBufferData(GL44.GL_ARRAY_BUFFER,vertData,GL44.GL_STATIC_DRAW);
|
||||
GL44.glVertexAttribPointer(0, 3, GL44.GL_FLOAT, false, 0, 0);
|
||||
GL44.glEnableVertexAttribArray(0);
|
||||
MemoryUtil.memFree(vertData);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FACES
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ELEMENT_ARRAY_BUFFER, faceBufferPtr);
|
||||
elementCount = data.elements.size();
|
||||
try {
|
||||
IntBuffer elementArrayBufferData = stackLocal.mallocInt(elementCount);
|
||||
for(int element : data.elements){
|
||||
elementArrayBufferData.put(element);
|
||||
}
|
||||
elementArrayBufferData.flip();
|
||||
GL44.glBufferData(GL45.GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferData,GL44.GL_STATIC_DRAW);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
//
|
||||
// FACES
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ELEMENT_ARRAY_BUFFER, faceBufferPtr);
|
||||
elementCount = data.elements.size();
|
||||
try {
|
||||
IntBuffer elementArrayBufferData = MemoryUtil.memAllocInt(elementCount);
|
||||
for(int element : data.elements){
|
||||
elementArrayBufferData.put(element);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// NORMALS
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ARRAY_BUFFER, normBufferPtr);
|
||||
try {
|
||||
int normalCount = data.normals.size() / 3;
|
||||
FloatBuffer NormalArrayBufferData;
|
||||
if(normalCount > 0){
|
||||
NormalArrayBufferData = stackLocal.mallocFloat(normalCount * 3);
|
||||
for(float normalValue : data.normals){
|
||||
NormalArrayBufferData.put(normalValue);
|
||||
}
|
||||
NormalArrayBufferData.flip();
|
||||
GL44.glBufferData(GL44.GL_ARRAY_BUFFER,NormalArrayBufferData,GL44.GL_STATIC_DRAW);
|
||||
GL44.glVertexAttribPointer(1, 3, GL44.GL_FLOAT, false, 0, 0);
|
||||
GL44.glEnableVertexAttribArray(1);
|
||||
elementArrayBufferData.flip();
|
||||
GL44.glBufferData(GL45.GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferData,GL44.GL_STATIC_DRAW);
|
||||
MemoryUtil.memFree(elementArrayBufferData);
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// NORMALS
|
||||
//
|
||||
GL44.glBindBuffer(GL44.GL_ARRAY_BUFFER, normBufferPtr);
|
||||
try {
|
||||
int normalCount = data.normals.size() / 3;
|
||||
FloatBuffer NormalArrayBufferData;
|
||||
if(normalCount > 0){
|
||||
NormalArrayBufferData = MemoryUtil.memAllocFloat(normalCount * 3);
|
||||
for(float normalValue : data.normals){
|
||||
NormalArrayBufferData.put(normalValue);
|
||||
}
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
NormalArrayBufferData.flip();
|
||||
GL44.glBufferData(GL44.GL_ARRAY_BUFFER,NormalArrayBufferData,GL44.GL_STATIC_DRAW);
|
||||
GL44.glVertexAttribPointer(1, 3, GL44.GL_FLOAT, false, 0, 0);
|
||||
GL44.glEnableVertexAttribArray(1);
|
||||
MemoryUtil.memFree(NormalArrayBufferData);
|
||||
}
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -613,33 +612,6 @@ public class Mesh {
|
||||
(byte)0x13
|
||||
};
|
||||
|
||||
static class Triangle {
|
||||
int[] indices = new int[3]; //array of size 3
|
||||
|
||||
public Triangle(int index0, int index1, int index2){
|
||||
indices[0] = index0;
|
||||
indices[1] = index1;
|
||||
indices[2] = index2;
|
||||
}
|
||||
}
|
||||
|
||||
static class GridCell {
|
||||
Vector3f[] points = new Vector3f[8]; //array of size 8
|
||||
double[] val = new double[8]; //array of size 8
|
||||
public void setValues(
|
||||
Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4,
|
||||
Vector3f p5, Vector3f p6, Vector3f p7, Vector3f p8,
|
||||
double val1, double val2, double val3, double val4,
|
||||
double val5, double val6, double val7, double val8
|
||||
){
|
||||
points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4;
|
||||
points[4] = p5; points[5] = p6; points[6] = p7; points[7] = p8;
|
||||
val[0] = val1; val[1] = val2; val[2] = val3; val[3] = val4;
|
||||
val[4] = val5; val[5] = val6; val[6] = val7; val[7] = val8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected static int polygonize(
|
||||
@ -897,20 +869,6 @@ public class Mesh {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
static class TerrainChunkData {
|
||||
|
||||
List<Float> vertices;
|
||||
List<Float> normals;
|
||||
List<Integer> elements;
|
||||
|
||||
TerrainChunkData(List<Float> vertices, List<Float> normals, List<Integer> elements){
|
||||
this.vertices = vertices;
|
||||
this.normals = normals;
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO: more optimal key creation
|
||||
private static String getVertKeyFromPoints(float x, float y, float z){
|
||||
return x + "_" + y + "_" + z;
|
||||
@ -934,5 +892,7 @@ public class Mesh {
|
||||
rVal = rVal.mul(proportion0).add(new Vector3f(normal1).mul(proportion1));
|
||||
return rVal;
|
||||
}
|
||||
|
||||
static TerrainChunkData data = generateTerrainChunkData(new float[FluidSim.DIM * FluidSim.DIM * FluidSim.DIM]);
|
||||
|
||||
}
|
||||
|
||||
15
src/main/java/electrosphere/render/TerrainChunkData.java
Normal file
15
src/main/java/electrosphere/render/TerrainChunkData.java
Normal file
@ -0,0 +1,15 @@
|
||||
package electrosphere.render;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TerrainChunkData {
|
||||
List<Float> vertices;
|
||||
List<Float> normals;
|
||||
List<Integer> elements;
|
||||
|
||||
TerrainChunkData(List<Float> vertices, List<Float> normals, List<Integer> elements){
|
||||
this.vertices = vertices;
|
||||
this.normals = normals;
|
||||
this.elements = elements;
|
||||
}
|
||||
}
|
||||
11
src/main/java/electrosphere/render/Triangle.java
Normal file
11
src/main/java/electrosphere/render/Triangle.java
Normal file
@ -0,0 +1,11 @@
|
||||
package electrosphere.render;
|
||||
|
||||
public class Triangle {
|
||||
int[] indices = new int[3]; //array of size 3
|
||||
|
||||
public Triangle(int index0, int index1, int index2){
|
||||
indices[0] = index0;
|
||||
indices[1] = index1;
|
||||
indices[2] = index2;
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,5 @@
|
||||
#version 330 core
|
||||
|
||||
#define NR_POINT_LIGHTS 10
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
|
||||
@ -26,19 +24,7 @@ void main(){
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
|
||||
// //grab light intensity
|
||||
// float lightIntensity = calcLightIntensityTotal(norm);
|
||||
|
||||
// //get color of base texture
|
||||
// vec3 textureColor = vec3(1);
|
||||
|
||||
|
||||
// //calculate final color
|
||||
// vec3 finalColor = textureColor * lightIntensity;
|
||||
vec3 lightAmount = CalcDirLight(norm, viewDir);
|
||||
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
|
||||
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
|
||||
// }
|
||||
|
||||
vec3 color = vec3(0.3,0.7,0.9) * lightAmount;
|
||||
|
||||
@ -54,7 +40,6 @@ vec3 CalcDirLight(vec3 normal, vec3 viewDir){
|
||||
vec3 reflectDir = reflect(-lightDir, normal);
|
||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 0.6);
|
||||
// combine results
|
||||
// vec3 texColor = texture(material.diffuse, TexCoord).rgb;
|
||||
vec3 diffuse = dLDiffuse * diff;
|
||||
|
||||
vec3 specular = spec * color;
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
//Vertex Shader
|
||||
#version 330 core
|
||||
|
||||
//defines
|
||||
#define TEXTURE_MAP_SCALE 3.0
|
||||
|
||||
|
||||
//input buffers
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user