How can I link an OpenGL texture to CUDA?

I’ve been following along with some guides online for linking an OpenGL texture to CUDA, but I seem to have run into a problem with “cudaBindTextureToArray.” Whenever I call that function, it returns an invalid texture arguments.

I have pasted my code that I am using to link the texture to a CUDA graphics resource, a CUDA array, and a CUDA texture reference. Line 65 is where my error occurs.

/// <summary>
/// Defines a 2D OpenGL texture's handle data.
/// </summary>
struct HandleData
{
    GLuint GLHandle;
    cudaGraphicsResource* CudaHandle;
    cudaArray* CudaArray;
    uchar4* TextureMemory;
};

// .............

// create the OpenGL texture
glGenTextures( 1, &( handle->GLHandle ) );

// initialize the texture to be the given size
glBindTexture( GL_TEXTURE_2D, handle->GLHandle );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_POINT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_POINT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glBindTexture( GL_TEXTURE_2D, 0 );



// create the CUDA graphics resource (this is fine)
cudaError_t err = cudaGraphicsGLRegisterImage( &( handle->CudaHandle ), handle->GLHandle, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsNone );
if ( err != cudaSuccess )
{
    Logger::Log( "Failed to register GL texture. Reason: ", cudaGetErrorString( err ) );
    delete handle;
    return nullptr;
}

// map the CUDA graphics resource to a CUDA array (this is fine)
err = cudaGraphicsMapResources( 1, &( handle->CudaHandle ), nullptr );
if ( err != cudaSuccess )
{
    Logger::Log( "Failed to map graphics resource to array. Reason: ", cudaGetErrorString( err ) );
    delete handle;
    return nullptr;
}

// get the mapped array (this is fine)
err = cudaGraphicsSubResourceGetMappedArray( &( handle->CudaArray ), handle->CudaHandle, 0, 0 );
if ( err != cudaSuccess )
{
    Logger::Log( "Failed to get mapped array. Reason: ", cudaGetErrorString( err ) );
    delete handle;
    return nullptr;
}


// create the CUDA texture reference
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<uchar4>();
texture<uchar4, 2, cudaReadModeElementType> tex;
tex.addressMode[ 0 ] = cudaAddressModeClamp;
tex.addressMode[ 1 ] = cudaAddressModeClamp;
tex.filterMode = cudaFilterModePoint;


// bind the CUDA array to a texture object (THIS is where the error happens)
err = cudaBindTextureToArray( tex, handle->CudaArray, channelDesc );
if ( err != cudaSuccess )
{
    Logger::Log( "Failed to bind texture to array. Reason: ", cudaGetErrorString( err ) );
    delete handle;
    return nullptr;
}

TLDR version:

  1. I create the OpenGL texture and set its filter/wrap mode to be point-clamp.
  2. I register the texture with cudaGraphicsGLRegisterImage, which is successful.
  3. I map the resource with cudaGraphicsMapResources, which is successful.
  4. I get the mapped array with cudaGraphicsSubResourceGetMappedArray, which is successful.
  5. I create the channel description and texture reference. Specifically "texture"
  6. I attempt to bind the texture to the array using cudaBindTextureToArray, which is where the code fails.

If somebody could help me with this, I would be very grateful.

Do you actually need the channel format (‘channelDesc’) arg on line 65?

I show how to map a Renderbuffer to a CUDA array, bind it to a surface, launch a kernel here.

The example uses the squeaky clean GLFW+GLAD libraries.

Hacking the code to support a texture instead of a Renderbuffer+surface should be straightforward but it looks like your code is already complete.

According to the compiler I do not need the parameter, but even if I remove it I still get the “invalid texture” error. I took a look at your code, and the only difference is you seem to render to a surface. For my project that is not exactly ideal, so I was hoping to be able to render into a uchar4 array and then copy that to a cudaArray that is attached to the OpenGL texture.

Update: I didn’t even need to use “cudaBindTextureToArray.” I just needed to allocate memory to modify then copy that over to the cudaArray to have the information show up in the OpenGL texture. (The Y values were flipped, but that was an easy fix.)