java - 需要帮助添加 OpenCL(GPU 使用)

标签 java gpu cpu jocl jcuda

嗯,我决定更喜欢使用 GPU 而不是 CPU,特别是因为我正在开发游戏,并且我预计 FPS 会增加。问题是我不知道从哪里开始。我可以轻松实现 JOCL 或 JCUDA,但之后我不知道在哪里将其从使用 CPU 替换为 GPU。感谢帮助:)

最佳答案

您想要进行什么样的计算?如果这些是计算密集型的,例如 N 体重力实验,那么您可以简单地将变量复制到 GPU,然后计算,然后将结果复制回主内存。

如果您的对象具有大数据但计算量小(例如流体动力学或碰撞检测),那么您应该在图形 api 和计算 api 之间添加互操作性。然后你就可以只进行计算,而无需复制任何数据。(加速就像你的GPU RAM带宽除以你的PCI-E带宽。对于HD7870,如果计算能力尚未饱和,它就像25倍)

我在 java 中使用了 jocl 和 lwjgl,利用 gl/cl 互操作性,它们工作得很好。

一些神经网络是用CPU(Encog)训练的,但由GPU(jocl)使用来生成 map 并由LWJGL绘制:(神经元权重稍微改变以产生更多随机化效果)

enter image description here

enter image description here

非常重要的部分是:

  • 启动 GL 上下文。
  • 使用 GL 上下文的句柄变量来启动可互操作的 CL 上下文
  • 创建 GL 缓冲区
  • 使用可互操作的 cl 上下文创建 CL 缓冲区。
  • 当 opencl 完成并且 gl 准备好启动时,不要忘记调用 clFinish()
  • 当 opengl 完成并且 cl 准备好启动时,不要忘记调用 glFinish()
  • 当您有数十个不同的内核、gl 和 cl 之间有许多不同的缓冲区并且需要它们按顺序运行时,使用 opencl 内核构建器/表类和缓冲区调度程序类会有所帮助。

示例:

 // clh is a fictional class that binds oepncl to opengl through interoperability
 // registering needed kernels to this object
 clh.addKernel(
               kernelFactory.fluidDiffuse(1024,1024),  // enumaration is fluid1
               kernelFactory.fluidAdvect(1024,1024),   // enumeration is fluid2
               kernelFactory.rigidBodySphereSphereInteracitons(2048,32,32), 
               kernelFactory.fluidRigidBodyInteractions(false), // fluidRigid
               kernelFactory.rayTracingShadowForFluid(true),
               kernelFactory.rayTracingBulletTargetting(true),
               kernelFactory.gravity(G),
               kernelFactory.gravitySphereSphere(), // enumeration is fall
               kernelFactory.NNBotTargetting(3,10,10,2,numBots) // Encog
               );

 clh.addBuffers(
         // enumeration is buf1 and is used as fluid1, fluid2 kernels' arguments
               bufferFactory.fluidSurfaceVerticesPosition(1024,1024, fluid1, fluid2),
        // enumeration is buf2, used by fluid1 and fluid2
               bufferFactory.fluidSurfaceColors(1024,1024,fluid1, fluid2),
        // enumeration is buf3, used by network
               bufferFactory.NNBotTargetting(numBots*25, Encog)
               )

 Running kernels:

 // shortcut of a sequence of kernels
 int [] fluidCalculations = new int[]{fluid1,fluid2,fluidRigid, fluid1} 

 clh.run(fluidCalculations); // runs the registered kernels
 // diffuses, advects, sphere-fluid interaction, diffuse again

 //When any update of GPU-buffer from main-memory is needed:

 clh.sendData(cpuBuffer, buf1); // updates fluid surface position from main-memory.

将 cpu 代码更改为 opencl 代码可以通过 APARAPI 自动完成,但我不确定它是否具有互操作性。

如果您需要自己做,那么很简单:

 From Java:

 for(int i=0;i<numParticles;i++)
 {
     for(int j=0;j<numParticles;j++)
       {

           particle.get(i).calculateAndAddForce(particle.get(j));
       }
 }


 To a Jocl kernel string(actually very similar to calculateAndAddForce's inside):

   "__kernel void nBodyGravity(__global float * positions,__global float *forces)" +
                "{" +
                "    int indis=get_global_id(0);" +
                "    int totalN=" + n + "; "+            
                "    float x0=positions[0+3*(indis)];"+
                "    float y0=positions[1+3*(indis)];"+
                "    float z0=positions[2+3*(indis)];"+
                "    float fx=0.0f;" +
                "    float fy=0.0f;" +
                "    float fz=0.0f;" +
                "    for(int i=0;i<totalN;i++)" +
                "    { "+
                "       float x1=positions[0+3*(i)];" +
                "       float y1=positions[1+3*(i)];" +
                "       float z1=positions[2+3*(i)];" +

                "       float dx = x0-x1;" +
                "       float dy = y0-y1;" +
                "       float dz = z0-z1;" +
                "       float r=sqrt(dx*dx+dy*dy+dz*dz+0.01f);" +
                "       float tr=0.1f/r;" +
                "       float tr2=tr*tr*tr;" +
                "       fx+=tr2*dx*0.0001f;" +
                "       fy+=tr2*dy*0.0001f;" +
                "       fz+=tr2*dz*0.0001f;" +

                "    } "+


                "    forces[0+3*(indis)]+=fx; " +
                "    forces[1+3*(indis)]+=fy; " +
                "    forces[2+3*(indis)]+=fz; " +

               "}"

关于java - 需要帮助添加 OpenCL(GPU 使用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18775601/

相关文章:

java - 如何用 Java 下载并解压 ZIP 文件

c++ - 最佳 GPU 性能的理想位图大小?

cpu - echo $$>尝试使用cpuset时,任务会给出 "no space left on device"

Java DataInputStream.read() 在被阻塞时导致 20% 的持续 CPU 使用率。

pytorch - 切换 GPU 设备会影响 PyTorch 反向传播中的梯度吗?

c - 从 AMD 主机调试在 Intel 目标上运行的 linux 内核 - 如何将控制权返回给 gdb?

java - 使用 dynamodb 映射器将属性投影到索引

java - 执行服务 shutdownNow ,它是如何工作的

java - 当我将字符串拆分为 2 个单词并交换它们时出现错误

cuda - 硬件 warp 调度程序如何形成和处理 warp?