好吧,我决定我更喜欢使用 GPU 而不是 CPU,尤其是因为我正在开发一款游戏,而我期望的 FPS 会增加。问题是我不知道从哪里开始。我可以轻松实现 JOCL 或 JCUDA,但之后我不知道在哪里将它从使用 CPU 替换为 GPU。帮助表示赞赏:)
问问题
801 次
1 回答
1
你追求什么样的计算?如果这些是计算密集型的,例如 N 体重力实验,那么您可以简单地将变量复制到 gpu,然后计算,然后将结果复制回主存。
如果您的对象具有大数据但计算量很小,例如流体动力学或碰撞检测,那么您应该在图形 api 和计算 api 之间添加互操作性。然后你可以只进行计算而不复制任何数据。(加速就像你的 GPU ram 带宽除以你的 pci-e 带宽。对于 HD7870,如果计算能力尚未饱和,它就像 25 倍)
我在 java 中使用 gl/cl 互操作性使用了 jocl 和 lwjgl,它们工作得很好。
一些神经网络使用 CPU(Encog) 进行训练,但被 GPU(jocl) 用于生成地图并由 LWJGL 绘制:(神经元权重稍作改变以产生更多随机化效果)
非常重要的部分是:
- 启动 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.
APARAPI 可以自动将 cpu 代码更改为 opencl 代码,但我不确定它是否具有互操作性。
如果您需要自己做,那么它很简单:
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; " +
"}"
于 2013-09-18T13:28:42.683 回答