Hi everyone.
I’m currently trying to get a combination of an QGLWidget showing an OpenGL texture which was modified by a CUDA kernel to work :cool:.
So, once again, I want to have a texture, modify it in some ways with CUDA kernels working on it, and display it in a QGLWidget, having OpenGL as the interface to both of them.
Basically, I was trying to get some of NVIDIA’s examples (SobelFilter) to work in an QGLWidget.
My steps so far:
init():
-
load the texture (tried QImage and cutLoadPPM4ub)
-
generate pixel buffer object (pbo)
-
bind pbo and copy the data
-
register the buffer as cuda_resource
-
generate and bind texture object
display():
-
cudaGraphicsMapResources()
-
cudaGraphicsResourceGetMappedPointer()
-
CUDA kernel working on the date behind the pointer
-
cudaGraphicsUnmapResources()
-
bind texture and buffer
-
use glTexImage2D()
-
draw the texture onto a quad
Well, I tried many combinations of the above steps, going one line after another through the examples NVIDIA provided with their CUDA SDK.
But I can’t get it to work.
Most of the time I see a black square, nothing more. If I play around with the pointers to show and so on, I can sometimes see the picture of some uninitialized memory :).
But I newer saw the picture/texture after it was altered by the CUDA kernel, I newer saw it after the sobel filter.
If I give the pointer to the texture pixels to glTexImage2D() and don’t do the memset, I can see the picture. But without filtering, of course. Like this
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, m_pQImage.width(), m_pQImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
So I believe, that the steps until this point are not totally wrong.
-
Has anybody done sth. like that already and can provide some useful hints?
-
I also habe concerns about double buffering and the correct use of swapBuffers()…
Any help is appreciated :).
Here a the three most important functions of my QGLWidget subclass:
the init() function:
void GLWidget::initializeGL()
{
makeCurrent();
m_pQImage = QGLWidget::convertToGLFormat(m_pQImage);
cudaGLSetGLDevice (cutGetMaxGflopsDeviceId() );
glewInit();
unsigned int w, h;
const char* image_filename = getImagePath();
if (cutLoadPPM4ub(image_filename, &pixels, &w, &h) != CUTTrue) {
printf("Failed to load image file: %s\n", image_filename);
exit(-1);
}
GLint bsize;
setupTexture(m_pQImage.width(), m_pQImage.height(), pixels, 4);
memset(pixels, 0x0, 4 * sizeof(Pixel) * m_pQImage.width() * m_pQImage.height());
glGenBuffers(1, &pbo_buffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER,
4 * sizeof(Pixel) * m_pQImage.width() * m_pQImage.height(),
pixels, GL_STREAM_DRAW);
glGetBufferParameteriv(GL_PIXEL_UNPACK_BUFFER, GL_BUFFER_SIZE, &bsize);
if ((GLuint)bsize != (4 * sizeof(Pixel) * m_pQImage.width() * m_pQImage.height()))
{
printf("Buffer object (%d) has incorrect size (%d).\n", (unsigned)pbo_buffer, (unsigned)bsize);
cudaThreadExit();
exit(-1);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// register this buffer object with CUDA
cutilSafeCall(cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, pbo_buffer, cudaGraphicsMapFlagsWriteDiscard));
glGenTextures (1, &m_pTexture);
glBindTexture (GL_TEXTURE_2D, m_pTexture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, m_pQImage.width(), m_pQImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture (GL_TEXTURE_2D, 0);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
}
the display() function:
void GLWidget::paintGL()
{
qDebug() << "paintGL()";
makeCurrent();
// Sobel operation
Pixel *data = NULL;
// map PBO to get CUDA device pointer
cutilSafeCall(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
size_t num_bytes;
cutilSafeCall(cudaGraphicsResourceGetMappedPointer((void **)&data, &num_bytes,
cuda_pbo_resource));
qDebug() << QString("CUDA mapped PBO: May access %1 bytes").arg(num_bytes);
sobelFilter(data, m_pQImage.width(), m_pQImage.height(), SOBELDISPLAY_IMAGE, 1.0f);
cutilSafeCall(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, m_pTexture);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, 0, 0, m_pQImage.width(), m_pQImage.height(),
GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL /*= OFFSET*/);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
swapBuffers();
}
the reshape() function:
void GLWidget::resizeGL(int iWidth, int iHeight)
{
makeCurrent();
int iSide = qMin(iWidth, iHeight);
glViewport((iWidth - iSide) / 2, (iHeight - iSide) / 2, iSide, iSide);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
setFixedSize(iWidth, iHeight);
}
I tried to build a little example, but you’ll have to set some path variables and the CUDA Build rules must be used of course.
UPDATED: For VS2008 you schould only have to set the Qt version:
[attachment=18572:QGLWidge…GLCUDAv2.zip]
THANKS!
QGLWidgetOpenGLCUDAv2.zip (572 KB)