LWJGL 在 IDE 之外运行时发现不同的 OpenCL 安装

LWJGL finding different OpenCL installation when runing outside of IDE

我在 IntelliJ 中使用 java 作为一种爱好已经有一段时间了,并决定开始使用 OpenCL 进行并行计算。我很确定我在下载 LWJGL 库并将其添加到我的项目时没有出错,因为它总是可以编译。问题是当我 运行 程序时,它产生这个输出:

Platforms found: 1
Treating platform 140038554960288
    Platform name: Clover 
    Platform vendor: Mesa 
    Platform version: OpenCL 1.1 Mesa 20.1.5 
Error: -1
Exception in thread "main" java.lang.AssertionError: -1
    at ch.test.Test1.devices_gpu(Test1.java:71)
    at ch.test.Test1.treatPlatform(Test1.java:22)
    at ch.test.Test1.main(Test1.java:94)

程序使用 assert 检查每个 return 的 OpenCL 函数,如果没有 return CL_SUCCESS,则程序崩溃。这里的错误是CL_DEVICE_NOT_FOUND.

当我将项目导出为 jar 并 运行 它在我的 IDE 中时,它会产生相同的输出。但是,如果我将发出的命令 (/home/user/Downloads/jdk-14.0.2/bin/java -ea -Dfile.encoding=UTF-8 -jar /home/user/IdeaProjects/LWJGLTest/out/artifacts/LWJGLTest_jar/LWJGLTest.jar) 复制到控制台并 运行 那里的 jar,它会给我以下(预期的)输出:

user@user-desktop:~$ /home/user/Downloads/jdk-14.0.2/bin/java -ea -Dfile.encoding=UTF-8 -jar /home/user/IdeaProjects/LWJGLTest/out/artifacts/LWJGLTest_jar/LWJGLTest.jar
Platforms found: 1
Treating platform 140169617041680
    Platform name: NVIDIA CUDA
    Platform vendor: NVIDIA Corporation
    Platform version: OpenCL 1.2 CUDA 10.2.178
Error: 0
1
    Devices found: 1
        Name: GeForce GTX 1080

我使用 clinfo 查看我的计算机找到了哪些 OpenCL 平台:

user@user-desktop:~$ clinfo
Number of platforms                               1
  Platform Name                                   NVIDIA CUDA
  Platform Vendor                                 NVIDIA Corporation
  Platform Version                                OpenCL 1.2 CUDA 11.0.228
  Platform Profile                                FULL_PROFILE
  Platform Extensions                             cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_fp64 cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll cl_nv_copy_opts cl_nv_create_buffer cl_khr_int64_base_atomics cl_khr_int64_extended_atomics
  Platform Extensions function suffix             NV

  Platform Name                                   NVIDIA CUDA
Number of devices                                 1
  Device Name                                     GeForce GTX 1080
...

有趣的是,当我更改驱动程序(从开源到专有,反之亦然)时,clinfo 暂时找不到任何平台(当然直到我重新启动),但在 IntelliJ 中,代码生成相同的输出(并在安装 none 时找到平台!),而在 jar 中 运行 时未找到平台。

我尝试了几种不同的 JRE,但 none 在 IntelliJ 中工作。我也尝试过更改类路径,但似乎没有任何效果。

这一切都在 Linux Mint 19 下。当我在笔记本电脑上使用 Windows 执行相同操作时,没有任何问题,一切正常。 用于测试的代码:

package ch.test;

import org.lwjgl.PointerBuffer;
import org.lwjgl.opencl.CL22;

import java.nio.ByteBuffer;

public class Test1 {

    static int getNumOfPlatforms() {
        int[] buffer = new int[1];
        int error = CL22.clGetPlatformIDs(null, buffer);
        assert error == CL22.CL_SUCCESS;
        return buffer[0];
    }

    static void treatPlatform(long plat) {
        System.out.println("\tPlatform name: " + getPlatformParam(plat, CL22.CL_PLATFORM_NAME));
        System.out.println("\tPlatform vendor: " + getPlatformParam(plat, CL22.CL_PLATFORM_VENDOR));
        System.out.println("\tPlatform version: " + getPlatformParam(plat, CL22.CL_PLATFORM_VERSION));

        PointerBuffer devices = devices_gpu(plat);
        System.out.println("\tDevices found: " + devices.capacity());
        while(devices.hasRemaining()) {
            treatDevice(devices.get());
        }
    }


    static void treatDevice(long device) {
        System.out.println("\t\tName: " + deviceProperty(device, CL22.CL_DEVICE_NAME));
    }

    static String deviceProperty(long device, int prop) {
        PointerBuffer length = PointerBuffer.allocateDirect(1);
        CL22.clGetDeviceInfo(device, prop, (long[])null, length);

        ByteBuffer value = ByteBuffer.allocateDirect((int)length.get());
        CL22.clGetDeviceInfo(device, prop, value, null);
        StringBuilder builder = new StringBuilder(value.capacity());

        for(int i = 0; i < builder.capacity(); i++){
            builder.append((char)value.get());
        }

        return builder.toString();
    }

    static String getPlatformParam(long plat, int attr) {
        PointerBuffer length = PointerBuffer.allocateDirect(1);
        CL22.clGetPlatformInfo(plat, attr, (long[])null, length);

        ByteBuffer value = ByteBuffer.allocateDirect((int)length.get());
        CL22.clGetPlatformInfo(plat, attr, value, null);
        StringBuilder builder = new StringBuilder(value.capacity());

        for(int i = 0; i < builder.capacity(); i++){
            builder.append((char)value.get());
        }

        return builder.toString();
    }

    static PointerBuffer devices_gpu(long plat) {
        int error;
        int[] amount = new int[]{-1};
        error = CL22.clGetDeviceIDs(plat, CL22.CL_DEVICE_TYPE_ALL, null, amount);
        System.out.println("Error: " + error);
        assert error == CL22.CL_SUCCESS: error;
        
        System.out.println(amount[0]);

        PointerBuffer devices = PointerBuffer.allocateDirect(amount[0]);
        error = CL22.clGetDeviceIDs(plat, CL22.CL_DEVICE_TYPE_ALL, devices, (int[])null);
        assert error == CL22.CL_SUCCESS: error;

        return devices;
    }

    public static void main(String[] args) {
        int error;

        int amountOfPlatforms = getNumOfPlatforms();
        System.out.println("Platforms found: " + amountOfPlatforms);
        PointerBuffer platforms = PointerBuffer.allocateDirect(amountOfPlatforms);
        error = CL22.clGetPlatformIDs(platforms, (int[])null);
        assert error == CL22.CL_SUCCESS;

        while(platforms.hasRemaining()) {
            long plat = platforms.get();
            System.out.println("Treating platform " + plat);
            treatPlatform(plat);
        }
    }
}

虽然我没有找到确切的问题,但我通过从他们的网站重新安装 IntelliJ 解决了这个问题。看来我之前通过 Linux Mint Software Manager 完成的安装有问题。现在一切都很好 感谢阅读和帮助