哪些代码可以被转换为 OpenCL
遵守一些约定可以提高将 Java 代码转换为 OpenCL 的成功率.
下面的指南/限制仅针对 Kernel.run()
和其可及方法, 其它 Java 方法不受相关约束.
部分指南/限制可能在未来的 Aparapi 中移除/放松.
只有 Java 值类型中的 boolean
, byte
, short
, int
, long
, float
和对应的一维数组受支持, 对 double
的支持视情况而定. Aparapi 会在运行时检查显卡, 驱动和 OpenCL 版本等信息来决定是否支持 double
. 如果你的平台不支持 double
, Aparapi 将会退回至 Java 线程池模式运行.
值类型 char
不受支持.
内核代码可以 读写 值类型数组字段中的数据.
需要注意的是 Java 为了处理匿名内部类中的值类型数组可能会创建隐藏字段, 就好像它们是内核类的字段一样.
值类型数组字段只能由内核代码 读. 因为内核和其可及代码是以不确定的顺序并行执行的, 即使是在 Java 线程池模式下运行, 也不推荐对值类型数组结果进行修改.
静态常量字段可以被内核代码 读.
静态变量字段不支持 读写, 请考虑将其常量化.
只有一维数组受支持.
数组不能被其它局部变量引用或作为形参传递给方法.
不支持 Java 5新增的 foreach
语法, 因为这会对原数组进行浅拷贝.
直接通过 Java 对象而不是内核实例对其它数据进行操作都会使 Aparapi 不能把代码转换为 OpenCL.
上述规则的例外情况是, 你可以调用对象数组内元素的 getter 和 setter.
Aparapi 不支持静态方法.
不支持递归, 不论是直接还是间接的. Aparapi 会对 this 递归做静态检查, 但是开发者应自己注意而不是完全交给 Aparapi.
带有变长形参的方法不受支持.
重载方法 (同名不同参) 方法不受支持. 这是因为 OpenCL 基于 C99 而 C99 不支持方法重载.
内核基类内包含对几乎所有 java.lang.Math
类方法的封装层. 当 Aparapi 运行在线程池模式时调用这些方法会委托至 java.lang.Math
, 而运行在 OpenCL 模式时会被翻译成等价的 OpenCL.
异常处理不受支持.
实例化不受支持, 无论是数组或对象.
同步块和同步方法不受支持.
只有简单循环体和条件语句受支持. switch
, break
和 continue
不受支持.
不能将表达式返回值或方法返回值用于变量的初始化赋值. 例如下面的代码就不能运行至 GPU:
int foo(int a) {
// . . .
}
public void run() {
int z;
foo(z = 3);
}
这应被视为一种错误. 作为变通, 你应在变量初始化时就显式赋值, 即使是初始化为0.
OpenCL 基于 C99, 规范上与 Java 有很大不同, 不能认为所有 Java 代码都能在 OpenCL 中产生相同结果. 例如, Java 明确规定了下面的代码
arra[i++] = arrb[i++];
等价于
arra[i] = arrb[i+1];
i += 2;
但 C99/OpenCL 标准并没有做出如上规范, 所以这段代码的运行结果是未定义的.
当运行在 GPU 模式时, 数组越界访问不会导致 ArrayIndexOutOfBoundsException
, 除0运算等也不会抛出 ArithmeticException
. 这些行为的结果是无法预料的.