如何在 Jocl 中使用 cl_khr_gl_sharing?
How to use cl_khr_gl_sharing in Jocl?
我正在尝试编写实时光线追踪器。
我为此使用 Java 和 OpenGL 和 OpenCL 的 Jogamp 绑定(调用 Jogl 和 Jocl)。
我的 .cl 内核中已经有光线追踪代码并且运行良好。我将输出作为 FloatBuffer 并通过 glTexImage2D 将其传递给 OpenGL 纹理。现在我想实时,为了实现这个,我想删除在我的程序中发生两次的 FloatBuffer 副本(第一次 - 从 OpenCL 内核结果到 RAM,第二次从 RAM 到 OpenGL 纹理)。显然有一种方法可以直接从 OpenGL 纹理指向 OpenCL 缓冲区,导致所有计算都在 GPU 上进行。
我知道 OpenCL 有 cl_khr_gl_sharing 扩展,可以满足我的要求。但我无法理解如何在 Java Jogamp 绑定 (jocl/jogl) 中使用它。有人可以帮助我或提供一些示例 JAVA 代码(不是 C++,它在细节上确实不同)吗?
所以,经过几天的研究,我找到了如何去做。为任何感兴趣的人发布答案。
在 Jogl 的 GLEventListener 的 "init" 方法中,您可以创建 GL 上下文。您也必须在该方法中创建 CL 上下文。
我的示例代码:
public void init(GLAutoDrawable drawable) {
GL4 gl4 = drawable.getGL().getGL4();
gl4.glDisable(GL4.GL_DEPTH_TEST);
gl4.glEnable(GL4.GL_CULL_FACE);
gl4.glCullFace(GL4.GL_BACK);
buildScreenVAO(gl4);
FloatBuffer pixelBuffer = GLBuffers.newDirectFloatBuffer(width * height * 4);
this.textureIndex = GLUtils.initTexture(gl4, width, height, pixelBuffer);
this.samplerIndex = GLUtils.initSimpleSampler(gl4);
if (clContext == null) {
try {
gl4.glFinish();
this.clContext = CLGLContext.create(gl4.getContext());
this.clDevice = clContext.getMaxFlopsDevice();
//if (device.getExtensions().contains("cl_khr_gl_sharing"))
this.clCommandQueue = clDevice.createCommandQueue();
this.clProgram = clContext.createProgram(new FileInputStream(new File(ResourceLocator.getInstance().kernelsPath + "raytracer.cl"))).build(); // load sources, create and build program
this.clKernel = clProgram.createCLKernel("main");
this.clTexture = (CLGLTexture2d<FloatBuffer>) clContext.createFromGLTexture2d(GL4.GL_TEXTURE_2D, textureIndex, 0, Mem.WRITE_ONLY);
this.viewTransform = clContext.createFloatBuffer(16 * 4, Mem.READ_ONLY);
this.w = clContext.createFloatBuffer(1, Mem.READ_ONLY);
clKernel.putArg(clTexture).putArg(width).putArg(height).putArg(viewTransform).putArg(w);
fillViewTransform(viewTransform);
fillW(w);
clCommandQueue.putWriteBuffer(viewTransform, false);
clCommandQueue.putWriteBuffer(w, false);
clCommandQueue.putAcquireGLObject(clTexture);
clCommandQueue.put1DRangeKernel(clKernel, 0, width * height, 0);
clCommandQueue.putReleaseGLObject(clTexture);
} catch (Exception e) {
e.printStackTrace();
}
}
buildShaderProgram(gl4);
bindObjects(gl4);
}
核心线是:clContext.createFromGLTexture2d(GL4.GL_TEXTURE_2D, textureIndex, 0, Mem.WRITE_ONLY);
您应该为之前创建的 OpenGL 纹理创建一个 OpenCL 纹理对象。创建OpenGL纹理的代码:
gl4.glGenTextures(1, indexBuffer);
int textureIndex = indexBuffer.get();
indexBuffer.clear();
gl4.glBindTexture(GL4.GL_TEXTURE_2D, textureIndex);
gl4.glTexParameterf(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MIN_FILTER, GL4.GL_LINEAR);
gl4.glTexParameterf(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MAG_FILTER, GL4.GL_LINEAR);
gl4.glTexImage2D(GL4.GL_TEXTURE_2D, 0, GL4.GL_RGBA32F, width, height, 0, GL4.GL_RGBA, GL4.GL_FLOAT, pixelBuffer); //TODO
gl4.glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_BASE_LEVEL, 0);
gl4.glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MAX_LEVEL, 0);
int[] swizzle = new int[] { GL4.GL_RED, GL4.GL_GREEN, GL4.GL_BLUE, GL4.GL_ONE };
gl4.glTexParameterIiv(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_SWIZZLE_RGBA, swizzle, 0);
gl4.glBindTexture(GL4.GL_TEXTURE_2D, 0);
return textureIndex;
最后一点 - 您必须在 OpenCL 内核中使用正确的纹理参数数据类型。在我的例子中,内核方法具有以下签名:
kernel void main(write_only image2d_t dst, const uint width, const uint height, global float* viewTransform, global float* w){
并且我使用 write_imagef 内置 OpenCL 方法将浮点数据 (0.0f - 1.0f) 写入该纹理。
如果您对此方法感兴趣,请随时向我询问。
我正在尝试编写实时光线追踪器。 我为此使用 Java 和 OpenGL 和 OpenCL 的 Jogamp 绑定(调用 Jogl 和 Jocl)。 我的 .cl 内核中已经有光线追踪代码并且运行良好。我将输出作为 FloatBuffer 并通过 glTexImage2D 将其传递给 OpenGL 纹理。现在我想实时,为了实现这个,我想删除在我的程序中发生两次的 FloatBuffer 副本(第一次 - 从 OpenCL 内核结果到 RAM,第二次从 RAM 到 OpenGL 纹理)。显然有一种方法可以直接从 OpenGL 纹理指向 OpenCL 缓冲区,导致所有计算都在 GPU 上进行。 我知道 OpenCL 有 cl_khr_gl_sharing 扩展,可以满足我的要求。但我无法理解如何在 Java Jogamp 绑定 (jocl/jogl) 中使用它。有人可以帮助我或提供一些示例 JAVA 代码(不是 C++,它在细节上确实不同)吗?
所以,经过几天的研究,我找到了如何去做。为任何感兴趣的人发布答案。
在 Jogl 的 GLEventListener 的 "init" 方法中,您可以创建 GL 上下文。您也必须在该方法中创建 CL 上下文。 我的示例代码:
public void init(GLAutoDrawable drawable) {
GL4 gl4 = drawable.getGL().getGL4();
gl4.glDisable(GL4.GL_DEPTH_TEST);
gl4.glEnable(GL4.GL_CULL_FACE);
gl4.glCullFace(GL4.GL_BACK);
buildScreenVAO(gl4);
FloatBuffer pixelBuffer = GLBuffers.newDirectFloatBuffer(width * height * 4);
this.textureIndex = GLUtils.initTexture(gl4, width, height, pixelBuffer);
this.samplerIndex = GLUtils.initSimpleSampler(gl4);
if (clContext == null) {
try {
gl4.glFinish();
this.clContext = CLGLContext.create(gl4.getContext());
this.clDevice = clContext.getMaxFlopsDevice();
//if (device.getExtensions().contains("cl_khr_gl_sharing"))
this.clCommandQueue = clDevice.createCommandQueue();
this.clProgram = clContext.createProgram(new FileInputStream(new File(ResourceLocator.getInstance().kernelsPath + "raytracer.cl"))).build(); // load sources, create and build program
this.clKernel = clProgram.createCLKernel("main");
this.clTexture = (CLGLTexture2d<FloatBuffer>) clContext.createFromGLTexture2d(GL4.GL_TEXTURE_2D, textureIndex, 0, Mem.WRITE_ONLY);
this.viewTransform = clContext.createFloatBuffer(16 * 4, Mem.READ_ONLY);
this.w = clContext.createFloatBuffer(1, Mem.READ_ONLY);
clKernel.putArg(clTexture).putArg(width).putArg(height).putArg(viewTransform).putArg(w);
fillViewTransform(viewTransform);
fillW(w);
clCommandQueue.putWriteBuffer(viewTransform, false);
clCommandQueue.putWriteBuffer(w, false);
clCommandQueue.putAcquireGLObject(clTexture);
clCommandQueue.put1DRangeKernel(clKernel, 0, width * height, 0);
clCommandQueue.putReleaseGLObject(clTexture);
} catch (Exception e) {
e.printStackTrace();
}
}
buildShaderProgram(gl4);
bindObjects(gl4);
}
核心线是:clContext.createFromGLTexture2d(GL4.GL_TEXTURE_2D, textureIndex, 0, Mem.WRITE_ONLY);
您应该为之前创建的 OpenGL 纹理创建一个 OpenCL 纹理对象。创建OpenGL纹理的代码:
gl4.glGenTextures(1, indexBuffer);
int textureIndex = indexBuffer.get();
indexBuffer.clear();
gl4.glBindTexture(GL4.GL_TEXTURE_2D, textureIndex);
gl4.glTexParameterf(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MIN_FILTER, GL4.GL_LINEAR);
gl4.glTexParameterf(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MAG_FILTER, GL4.GL_LINEAR);
gl4.glTexImage2D(GL4.GL_TEXTURE_2D, 0, GL4.GL_RGBA32F, width, height, 0, GL4.GL_RGBA, GL4.GL_FLOAT, pixelBuffer); //TODO
gl4.glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_BASE_LEVEL, 0);
gl4.glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MAX_LEVEL, 0);
int[] swizzle = new int[] { GL4.GL_RED, GL4.GL_GREEN, GL4.GL_BLUE, GL4.GL_ONE };
gl4.glTexParameterIiv(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_SWIZZLE_RGBA, swizzle, 0);
gl4.glBindTexture(GL4.GL_TEXTURE_2D, 0);
return textureIndex;
最后一点 - 您必须在 OpenCL 内核中使用正确的纹理参数数据类型。在我的例子中,内核方法具有以下签名:
kernel void main(write_only image2d_t dst, const uint width, const uint height, global float* viewTransform, global float* w){
并且我使用 write_imagef 内置 OpenCL 方法将浮点数据 (0.0f - 1.0f) 写入该纹理。
如果您对此方法感兴趣,请随时向我询问。