diff --git a/src/main/java/com/aparapi/Config.java b/src/main/java/com/aparapi/Config.java
index 0986dcfd..75f7b530 100644
--- a/src/main/java/com/aparapi/Config.java
+++ b/src/main/java/com/aparapi/Config.java
@@ -159,6 +159,8 @@ public class Config extends ConfigJNI{
public static final boolean enableARRAY = !Boolean.getBoolean(propPkgName + ".disable.ARRAY");
+ public static final boolean enableVECTOR = !Boolean.getBoolean(propPkgName + ".disable.VECTOR");
+
public static final boolean enableNEW = Boolean.getBoolean(propPkgName + ".enable.NEW");
public static final boolean enableATHROW = Boolean.getBoolean(propPkgName + ".enable.ATHROW");
diff --git a/src/main/java/com/aparapi/Kernel.java b/src/main/java/com/aparapi/Kernel.java
index f697ff4a..ab5fc2db 100644
--- a/src/main/java/com/aparapi/Kernel.java
+++ b/src/main/java/com/aparapi/Kernel.java
@@ -329,6 +329,14 @@ public abstract class Kernel implements Cloneable {
boolean atomic64() default false;
}
+ /**
+ * This annotation is for internal use only
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface OpenCLMappingPattern {
+ String mapTo() default "";
+ }
+
public abstract class Entry {
public abstract void run();
@@ -2612,7 +2620,7 @@ private static String toClassShortNameIfAny(final Class> retClass) {
final String mapping = typeToLetterMap.get(strRetClass);
// System.out.println("strRetClass = <" + strRetClass + ">, mapping = " + mapping);
if (mapping == null)
- return "[" + retClass.getName() + ";";
+ return "L" + retClass.getName() + ";";
return mapping;
}
@@ -2688,6 +2696,38 @@ public static boolean isOpenCLDelegateMethod(MethodReferenceEntry methodReferenc
return (isMapped);
}
+ public static String getMethodMappedPattern(MethodReferenceEntry _methodReferenceEntry) {
+ final String name = _methodReferenceEntry.getClassEntry().getNameUTF8Entry().getUTF8().replace("/",".");
+
+ final Class> currentClass;
+ try {
+ currentClass = Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+
+ String methodSignature = toSignature(_methodReferenceEntry).replace("/", ".");
+
+ //System.out.println("? - "+methodSignature);
+
+ for (final Method method : currentClass.getMethods()) {
+ if (method.isAnnotationPresent(OpenCLMappingPattern.class)) {
+
+ //System.out.println(toSignature(method));
+
+ if (methodSignature.equals(toSignature(method))) {
+ final OpenCLMappingPattern annotation = method.getAnnotation(OpenCLMappingPattern.class);
+ final String mapTo = annotation.mapTo();
+ if (!mapTo.equals("")) {
+ return mapTo;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
public static boolean usesAtomic32(MethodReferenceEntry methodReferenceEntry) {
if (CacheEnabler.areCachesEnabled())
return getProperty(atomic32Cache, methodReferenceEntry, false);
diff --git a/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java b/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java
index 23543349..dd5e01bb 100644
--- a/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java
+++ b/src/main/java/com/aparapi/internal/jni/KernelArgJNI.java
@@ -46,6 +46,11 @@ public abstract class KernelArgJNI{
* @see KernelRunnerJNI#ARG_EXPLICIT
* @see KernelRunnerJNI#ARG_EXPLICIT_WRITE
* @see KernelRunnerJNI#ARG_OBJ_ARRAY_STRUCT
+ * @see KernelRunnerJNI#ARG_VECTOR_2
+ * @see KernelRunnerJNI#ARG_VECTOR_3
+ * @see KernelRunnerJNI#ARG_VECTOR_4
+ * @see KernelRunnerJNI#ARG_VECTOR_8
+ * @see KernelRunnerJNI#ARG_VECTOR_16
*/
@UsedByJNICode protected int type;
diff --git a/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java b/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java
index 2ef6a54f..7c92040c 100644
--- a/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java
+++ b/src/main/java/com/aparapi/internal/jni/KernelRunnerJNI.java
@@ -236,14 +236,64 @@ public abstract class KernelRunnerJNI{
/**
* This 'bit' indicates that a particular KernelArg
represents a static
field (array or primitive).
- *
- *
+ *
+ *
* @see com.aparapi.internal.annotation.UsedByJNICode
- *
+ *
* @author gfrost
*/
@UsedByJNICode protected static final int ARG_STATIC = 1 << 22;
+ /**
+ * This 'bit' indicates that a particular KernelArg
represents a vector2
field (array or primitive).
+ *
+ *
+ * @see com.aparapi.internal.annotation.UsedByJNICode
+ *
+ * @author gfrost
+ */
+ @UsedByJNICode protected static final int ARG_VECTOR_2 = 1 << 25;
+
+ /**
+ * This 'bit' indicates that a particular KernelArg
represents a vector3
field (array or primitive).
+ *
+ *
+ * @see com.aparapi.internal.annotation.UsedByJNICode
+ *
+ * @author gfrost
+ */
+ @UsedByJNICode protected static final int ARG_VECTOR_3 = 1 << 26;
+
+ /**
+ * This 'bit' indicates that a particular KernelArg
represents a vector4
field (array or primitive).
+ *
+ *
+ * @see com.aparapi.internal.annotation.UsedByJNICode
+ *
+ * @author gfrost
+ */
+ @UsedByJNICode protected static final int ARG_VECTOR_4 = 1 << 27;
+
+ /**
+ * This 'bit' indicates that a particular KernelArg
represents a vector8
field (array or primitive).
+ *
+ *
+ * @see com.aparapi.internal.annotation.UsedByJNICode
+ *
+ * @author gfrost
+ */
+ @UsedByJNICode protected static final int ARG_VECTOR_8 = 1 << 28;
+
+ /**
+ * This 'bit' indicates that a particular KernelArg
represents a vector16
field (array or primitive).
+ *
+ *
+ * @see com.aparapi.internal.annotation.UsedByJNICode
+ *
+ * @author gfrost
+ */
+ @UsedByJNICode protected static final int ARG_VECTOR_16 = 1 << 29;
+
/**
* This 'bit' indicates that we wish to enable profiling from the JNI code.
*
diff --git a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
index 66f8e72b..d7679369 100644
--- a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
+++ b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
@@ -65,6 +65,7 @@ to national security controls as identified on the Commerce Control List (curren
import com.aparapi.internal.writer.*;
import com.aparapi.opencl.*;
+import com.aparapi.opencl.vector.Float2;
import java.lang.reflect.*;
import java.nio.*;
import java.util.*;
@@ -943,7 +944,24 @@ private void extractOopConversionBuffer(KernelArg arg) throws AparapiException {
private void restoreObjects() throws AparapiException {
for (int i = 0; i < argc; i++) {
final KernelArg arg = args[i];
- if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) {
+
+ //TODO: code it properly
+ if ((arg.getType() & ARG_VECTOR_2) != 0) {
+ Object obj = arg.getArray();
+
+ float[] array = (float[])obj;
+
+ try {
+ Float2[] ref = (Float2[])arg.getField().get(kernel);
+
+ for (int j = 0; j < ref.length; j++) {
+ ref[j] = Float2.create(array[j * 2 + 0], array[j * 2 + 1]);
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ } else if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) {
extractOopConversionBuffer(arg);
}
}
@@ -979,6 +997,11 @@ private boolean updateKernelArrayRefs() throws AparapiException {
if ((arg.getType() & ARG_OBJ_ARRAY_STRUCT) != 0) {
prepareOopConversionBuffer(arg);
} else {
+ //TODO: handle vectors
+ if ((arg.getType() & ARG_VECTOR_2) != 0) {
+ usesOopConversion = true;
+ newArrayRef = new float[arrayLength * 2];
+ }
// set up JNI fields for normal arrays
arg.setJavaArray(newArrayRef);
arg.setNumElements(arrayLength);
@@ -1415,9 +1438,19 @@ else if (Config.enableShowGeneratedOpenCL) {
// args[i].type |= ARG_GLOBAL;
if (type.getName().startsWith("[L")) {
- args[i].setArray(null); // will get updated in updateKernelArrayRefs
- args[i].setType(args[i].getType()
- | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ));
+ //TODO: get flags from annotation
+ if ("[Lcom.aparapi.opencl.vector.Float2;".equals(type.getName())) {
+ args[i].setArray(null);
+ args[i].setType(
+ args[i].getType() | (ARG_ARRAY | ARG_FLOAT | ARG_VECTOR_2 | ARG_WRITE | ARG_READ)
+ );
+ } else {
+ // will get updated in updateKernelArrayRefs
+ args[i].setArray(null);
+ args[i].setType(
+ args[i].getType() | (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)
+ );
+ }
if (logger.isLoggable(Level.FINE)) {
logger.fine("tagging " + args[i].getName() + " as (ARG_ARRAY | ARG_OBJ_ARRAY_STRUCT | ARG_WRITE | ARG_READ)");
@@ -1633,24 +1666,39 @@ private int getCurrentPassLocal() {
}
private int getPrimitiveSize(int type) {
+ int size = 0;
if ((type & ARG_FLOAT) != 0) {
- return 4;
+ size = 4;
} else if ((type & ARG_INT) != 0) {
- return 4;
+ size = 4;
} else if ((type & ARG_BYTE) != 0) {
- return 1;
+ size = 1;
} else if ((type & ARG_CHAR) != 0) {
- return 2;
+ size = 2;
} else if ((type & ARG_BOOLEAN) != 0) {
- return 1;
+ size = 1;
} else if ((type & ARG_SHORT) != 0) {
- return 2;
+ size = 2;
} else if ((type & ARG_LONG) != 0) {
- return 8;
+ size = 8;
} else if ((type & ARG_DOUBLE) != 0) {
- return 8;
+ size = 8;
}
- return 0;
+
+ int vectorFactor = 1;
+ if ((type & ARG_VECTOR_2) != 0) {
+ vectorFactor = 2;
+ } else if ((type & ARG_VECTOR_3) != 0) {
+ vectorFactor = 3;
+ } else if ((type & ARG_VECTOR_4) != 0) {
+ vectorFactor = 4;
+ } else if ((type & ARG_VECTOR_8) != 0) {
+ vectorFactor = 8;
+ } else if ((type & ARG_VECTOR_16) != 0) {
+ vectorFactor = 16;
+ }
+
+ return size * vectorFactor;
}
private void setMultiArrayType(KernelArg arg, Class> type) throws AparapiException {
diff --git a/src/main/java/com/aparapi/internal/model/Entrypoint.java b/src/main/java/com/aparapi/internal/model/Entrypoint.java
index 3a291b24..0e11e65e 100644
--- a/src/main/java/com/aparapi/internal/model/Entrypoint.java
+++ b/src/main/java/com/aparapi/internal/model/Entrypoint.java
@@ -477,7 +477,7 @@ public Entrypoint(ClassModel _classModel, MethodModel _methodModel, Object _k) t
for (final MethodCall methodCall : methodModel.getMethodCalls()) {
ClassModelMethod m = resolveCalledMethod(methodCall, classModel);
- if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m)) {
+ if ((m != null) && !methodMap.keySet().contains(m) && !noCL(m) && !isInternal(m)) {
final MethodModel target = new MethodModel(m, this);
methodMap.put(m, target);
methodModel.getCalledMethods().add(target);
@@ -805,10 +805,14 @@ else if (instruction instanceof I_INVOKEVIRTUAL) {
}
private boolean noCL(ClassModelMethod m) {
- boolean found = m.getClassModel().getNoCLMethods().contains(m.getName());
- return found;
+ return m.getClassModel().getNoCLMethods().contains(m.getName());
}
+ private boolean isInternal(ClassModelMethod m) {
+ //TODO: use mapped cache
+ return m.getOwnerClassModel().getClassWeAreModelling().getName().startsWith("com.aparapi.opencl.vector");
+ }
+
private FieldEntry getSimpleGetterField(MethodModel method) {
return method.getAccessorVariableFieldEntry();
}
diff --git a/src/main/java/com/aparapi/internal/writer/KernelWriter.java b/src/main/java/com/aparapi/internal/writer/KernelWriter.java
index 8099c591..70fa5d4b 100644
--- a/src/main/java/com/aparapi/internal/writer/KernelWriter.java
+++ b/src/main/java/com/aparapi/internal/writer/KernelWriter.java
@@ -64,6 +64,7 @@ to national security controls as identified on the Commerce Control List (curren
import com.aparapi.internal.model.ClassModel.*;
import com.aparapi.internal.model.ClassModel.ConstantPool.*;
+import com.aparapi.internal.tool.InstructionHelper.StringWriter;
import java.util.*;
public abstract class KernelWriter extends BlockWriter{
@@ -160,7 +161,13 @@ public abstract class KernelWriter extends BlockWriter{
javaToCLIdentifierMap.put("globalBarrier()V", "barrier(CLK_GLOBAL_MEM_FENCE)");
}
- /**
+ private final static Map mapping = new HashMap<>();
+ static {
+ mapping.put("Lcom/aparapi/opencl/vector/Float2;", "float2");
+ }
+
+
+ /**
* These three convert functions are here to perform
* any type conversion that may be required between
* Java and OpenCL.
@@ -170,6 +177,11 @@ public abstract class KernelWriter extends BlockWriter{
* @return Suitably converted string, "char*", etc
*/
@Override public String convertType(String _typeDesc, boolean useClassModel, boolean isLocal) {
+ String mapTo = mapping.get(_typeDesc);
+ if (mapTo != null) {
+ return mapTo + " ";
+ }
+
if (_typeDesc.equals("Z") || _typeDesc.equals("boolean")) {
return (cvtBooleanToChar);
} else if (_typeDesc.equals("[Z") || _typeDesc.equals("boolean[]")) {
@@ -226,6 +238,26 @@ public abstract class KernelWriter extends BlockWriter{
write(barrierAndGetterMappings);
}
} else {
+ final String pattern = Kernel.getMethodMappedPattern(_methodEntry);
+ if (pattern != null) {
+ //System.out.println(pattern);
+
+ String[] params = new String[argc];
+
+ for (int arg = 0; arg < argc; arg++) {
+
+ StringWriter sw = new StringWriter();
+
+ sw.writeInstruction(_methodCall.getArg(arg));
+
+ params[arg] = sw.toString();
+ }
+
+ write(String.format(pattern, params));
+
+ return;
+ }
+
final boolean isSpecial = _methodCall instanceof I_INVOKESPECIAL;
MethodModel m = entryPoint.getCallTarget(_methodEntry, isSpecial);
@@ -381,15 +413,20 @@ public void writePragma(String _name, boolean _enable) {
}
// If it is a converted array of objects, emit the struct param
- String className = null;
if (signature.startsWith("L")) {
- // Turn Lcom/codegen/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example
- className = (signature.substring(1, signature.length() - 1)).replace('/', '_');
- // if (logger.isLoggable(Level.FINE)) {
- // logger.fine("Examining object parameter: " + signature + " new: " + className);
- // }
- argLine.append(className);
- thisStructLine.append(className);
+ String mapTo = mapping.get(signature);
+ if (mapTo != null) {
+ argLine.append(mapTo);
+ thisStructLine.append(mapTo);
+ } else {
+ // Turn Lcom/codegen/javalabs/opencl/demo/DummyOOA; into com_amd_javalabs_opencl_demo_DummyOOA for example
+ String className = (signature.substring(1, signature.length() - 1)).replace('/', '_');
+ // if (logger.isLoggable(Level.FINE)) {
+ // logger.fine("Examining object parameter: " + signature + " new: " + className);
+ // }
+ argLine.append(className);
+ thisStructLine.append(className);
+ }
} else {
argLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false, false));
thisStructLine.append(convertType(ClassModel.typeName(signature.charAt(0)), false, false));
diff --git a/src/main/java/com/aparapi/opencl/vector/Float2.java b/src/main/java/com/aparapi/opencl/vector/Float2.java
new file mode 100644
index 00000000..62b7c92d
--- /dev/null
+++ b/src/main/java/com/aparapi/opencl/vector/Float2.java
@@ -0,0 +1,54 @@
+package com.aparapi.opencl.vector;
+
+import com.aparapi.Kernel.OpenCLMappingPattern;
+
+public final class Float2 {
+
+ @OpenCLMappingPattern(mapTo = "(float2)( 0, 0 )")
+ public static Float2 create() {
+ return create(0f);
+ }
+
+ @OpenCLMappingPattern(mapTo = "(float2)( %1$s, %1$s )")
+ public static Float2 create(float n) {
+ return new Float2(n, n);
+ }
+
+ @OpenCLMappingPattern(mapTo = "(float2)( %s, %s )")
+ public static Float2 create(float x, float y) {
+ return new Float2(x, y);
+ }
+
+ public final float x;
+ public final float y;
+
+ private Float2(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @OpenCLMappingPattern(mapTo = "+")
+ public Float2 add(Float2 v1) {
+ return Float2.create(this.x + v1.x, this.y + v1.y);
+ }
+
+ @OpenCLMappingPattern(mapTo = "-")
+ public Float2 subtract(Float2 v1) {
+ return Float2.create(this.x - v1.x, this.y - v1.y);
+ }
+
+ @OpenCLMappingPattern(mapTo = "*")
+ public Float2 multiply(Float2 v1) {
+ return Float2.create(this.x * v1.x, this.y * v1.y);
+ }
+
+ @OpenCLMappingPattern(mapTo = "/")
+ public Float2 divide(Float2 v1) {
+ return Float2.create(this.x / v1.x, this.y / v1.y);
+ }
+
+ @OpenCLMappingPattern(mapTo = "%")
+ public Float2 remainder(Float2 v1) {
+ return Float2.create(this.x % v1.x, this.y % v1.y);
+ }
+}
diff --git a/src/test/java/com/aparapi/runtime/VectorTest.java b/src/test/java/com/aparapi/runtime/VectorTest.java
new file mode 100644
index 00000000..ce6e76dd
--- /dev/null
+++ b/src/test/java/com/aparapi/runtime/VectorTest.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2016 - 2017 Syncleus, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.aparapi.runtime;
+
+import static org.junit.Assert.assertEquals;
+
+import com.aparapi.Kernel;
+import com.aparapi.opencl.vector.Float2;
+import java.util.Arrays;
+import org.junit.Test;
+
+
+public class VectorTest {
+ @Test
+ public void test() {
+ VectorKernel b = new VectorKernel();
+ b.test();
+ }
+
+ public static class VectorKernel extends Kernel {
+ private static final int SIZE = 32;
+
+ final Float2[] target = new Float2[SIZE];
+
+ VectorKernel() {
+ for (int i = 0; i < SIZE; ++i) {
+ target[i] = Float2.create();
+ }
+ }
+
+ @Override
+ public void run() {
+ int id = getGlobalId();
+
+ final Float2 v = Float2.create(id, id * 2);
+ target[id] = v;
+ }
+
+ void validate() {
+ for (int i = 0; i < SIZE; i++) {
+
+ Float2 v = target[i];
+
+ assertEquals(i, v.x, 0.01f);
+ assertEquals(i * 2, v.y, 0.01f);
+ }
+ }
+
+ public void test() {
+ execute(SIZE);
+ validate();
+ }
+ }
+}