How to use cl_khr_gl_sharing in Jocl?

190 Views Asked by At

I'm trying to write real-time raytracer. I use Java and Jogamp bindings of OpenGL and OpenCL for it (calls Jogl and Jocl). I already have raytracing code in my .cl kernel and its works well. I get output as FloatBuffer and pass it to the OpenGL texture via glTexImage2D. Now I want to go realtime, and to achive this I want to remove FloatBuffer copy which happens twice in my program (first - from OpenCL kernel result to RAM, and second from RAM to OpenGL texture). Obvious there is a way to point OpenCL buffer from OpenGL texture direct, cause all calculations works on GPU. I know that there is cl_khr_gl_sharing extention for OpenCL which do what I want. But I can't understand how to use this in Java Jogamp bindings (jocl/jogl). Can somebody helps me or give some sample JAVA code (not C++ which is really differs in details)?

1

There are 1 best solutions below

0
On BEST ANSWER

So, after few days of research I find how to do it. Posting an answer for anybody who interest.

In "init" method of Jogl's GLEventListener you create GL context. You must create CL context in that method too. My sample code for this:

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); 
}

The core line is: clContext.createFromGLTexture2d(GL4.GL_TEXTURE_2D, textureIndex, 0, Mem.WRITE_ONLY); You should create an OpenCL texture object for your previous created OpenGL texture. Code of creating OpenGL texture:

        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;

And the last - you must use right data type of texture argument in your OpenCL kernel. In my case kernel method has the following signature:

kernel void main(write_only image2d_t dst, const uint width, const uint height, global float* viewTransform, global float* w){                                                                            

and I use write_imagef build-in OpenCL method to write float data (0.0f - 1.0f) into this texture.

Feel free to ask me about this approach if you interested.