How to convert an OpenCL buffer to an OpenGl 3D texture

Hi.

I would like to create a OpenGL 3D texture from OpenCL 3D buffer. Can do this within the kernel that fills the 3D buffer?


Dag Magne

I would like to create a OpenGL 3D texture from OpenCL 3D buffer.

As of today, interoperability between OpenGL and OpenCL is achieved the other way around: you must create an OpenGL object first, then create an OpenCL object out of the GL object.

Can do this within the kernel that fills the 3D buffer?

What you can do is create a 3D texture in OpenGL, then use clCreateFromGLTexture3D() to generate an OpenCL 3D image object that shares pixels with that 3D texture. Notice that you will have to pass some extra arguments to clCreateContext() if you want to share data with OpenGL. It’s explained in sections 9.7, 9.8 and 9.9 of the OpenCL 1.1. spec.

It seems that my (most?) OpenCL implementation does not support image_write to image3d_t images. Is there an alternative way to transfer the values in the OpenCL buffer to an (existing) OpenGL Texture, without copying data to the CPU?

Dag Magne

OK, I see.

You could create a CL 3D image object that is shared with GL as I described above, then use OpenCL to write data into a separate CL buffer object. Finally, clEnqueueCopyBufferToImage() would copy the data from the buffer to the GL texture.

The downside is that it does a copy. The upside is that all the operations occur in device memory so the cost is not as high.

I can’t think right now of a portable way to do the same without a copy.

Great! This was exactly what I was looking for, since I already have the OpenCL buffer and a 3D texture available :slight_smile:

Thank you David, for your quick response and good answers!


Dag Magne

Hi again. Today I have tried to use the clEnqueueCopyBufferToImage, but it fails (includes total PC crash) when trying to use an OpenCL image created from an OpenGL texture. (the same call seems to work OK when destination is an “ordinary” OpenCL-image created using clCreateImage3D)

I have also tried to copy the buffer back to CPU-memory and then call glTexImage3D, and this works - but is too slow.

Here is some of my code:

// creation of OpenGL texture
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_3D, textureId);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, GRIDSIZE, GRIDSIZE, GRIDSIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);

// creation of OpenCL image from OpenGl texture
m_openGlTexture = clCreateFromGLTexture3D(
m_clGPUContext,
CL_MEM_WRITE_ONLY,
GL_TEXTURE_3D,
0,
textureId,
&ciErrNum);

if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;
///////////////////////////////////////////////////////////////////////////////////////

// code called after kernel is runned, and m_cl_memout is filled

// Aquire OpenGL texture object
ciErrNum = clEnqueueAcquireGLObjects(m_clCommandQueue, 1, &m_openGlTexture, 0, NULL, NULL);
if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

ciErrNum = clFinish(m_clCommandQueue);
if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

// copy OpenCL buffer to OpenGl texture
size_t corigin[3] = {0,0,0};
size_t cregion[3] = {GRIDSIZE, GRIDSIZE, GRIDSIZE};
ciErrNum = clEnqueueCopyBufferToImage(m_clCommandQueue ,m_cl_memout, m_openGlTexture, 0, corigin, cregion, 0, NULL, NULL);
if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

ciErrNum = clFinish(m_clCommandQueue);
if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

// Release OpenGL texture object
ciErrNum = clEnqueueReleaseGLObjects(m_clCommandQueue, 1, &m_openGlTexture, 0, NULL, NULL);
if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

ciErrNum = clFinish(m_clCommandQueue);

if (ciErrNum != CL_SUCCESS)
std::cout << "ERROR: " << getErrorString(ciErrNum) << std::endl;

A small update from myself:

It seems from the “List of OpenGL and corresponding OpenCL Image Formats” in the OpenCL spec that the OpenCL 3d image created from my OpenGL texture with GL internal format RGB8, is a CL_RGBA, CL_UNORM_INT8 image.

My output buffer (m_cl_memout) was a unsigned char buffer with only one channel (i.e. alpha) and not a 4 channel (RGBA) buffer, so the clEnqueueCopyBufferToImage call would then access 4 times the allocated memory area… This might explain the program/system termination I have experienced. Extending the m_cl_memout buffer to support 4 channels seems to remove the program/system termination.

The downside of this is that the clEnqueueCopyBufferToImage has to copy 4 times the number of data that is needed. A writable single channel (R_A) OpenCL 3D image would be preferred :slight_smile:


Dag Magne