Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Channels ▼


CUDA, Supercomputing for the Masses: Part 18

Vertex Buffer Objects

Most of the PBO software framework described in Part 15 will be reused to demonstrate drawing with VBOs in this article. As with pixel buffer objects, high-speed interoperability is achieved by mapping OpenGL buffers into the CUDA memory space without requiring a memory copy. Detailed information about the API and OpenGL calls used when mixing CUDA with OpenGL can be found in the PBO article as well as Joe Stam's 2009 NVIDIA GTC conference presentation What Every CUDA Programmer Should Know About OpenGL (also available in video here).

Just as in the NVIDIA SDK samples, GLUT (a window system independent OpenGL Toolkit) was utilized for Windows and Linux compatibility. This article focuses on building and running the examples under Linux. Go here for more information about building these examples with Microsoft Visual Studio.

Figure 8 summarizes how the VBO example code interacts with GLUT. The boxes highlighted in green indicate those areas that required refactoring the original PBO code so it can work with VBOs.

Figure 8: Schematic of GLUT VBO code interactions.

The relationship between the four files used in the procedural framework discussed in this article is illustrated in Figure 9.

Figure 9: Organization of files and activities.

The simpleGLmain.cpp File

The file simplGLmain.cpp from Part 15 already provides all the boilerplate needed to open a window on the screen and set some basic viewing transforms sufficient to display the two-dimensional pictures created in our PBO examples.

From a coding point of view, adapting the 2D PBO version of simpleGLmain.cpp to display 3D VBO objects merely requires specifying a three-dimensional perspective in initGL with the call:

gluPerspective(60.0, (GLfloat)window_width/(GLfloat)window_height, 0.1, 1, 0.);

From an OpenGL point of view, adding a perspective with gluPerspective effectively places a camera in a three-dimensional location from which to view the data generated by our CUDA kernel(s). Three-dimensional rendering occurs on the GPU when the programmer:

  • Specifies objects in 3D space using simple triangles, vertices and lines.
  • Defines a virtual camera position and viewing angle.

The GPU can then identify and update the display pixels as the data and/or viewing position changes.

Continuing with the camera analogy, the required transforms for 3D data are:

  1. Position and point the camera at the scene (a view transformation)
  2. Arrange the scene composition (a model transform)
  3. Adjust the camera zoom (a projection transform)
  4. Choose the final size (a viewport transform)

OpenGL transforms and coordinate systems require very detailed thinking and explanation. Suffice it to say that defining the projection transform is all that was needed to adapt simplePBO.cpp so 3D VBO data can be displayed.

Song Ho Ann has an excellent set of tutorials and visual aids to help understand the details of OpenGL transforms, the OpenGL rendering pipeline (including differences between pixel and geometry rendering), the OpenGL projection matrix, and much more. I recommend these tutorials or one of the many other excellent resources available on the web including the online version of Chapter 3 of the OpenGL Red Book.

The following is the complete source code for the VBO version of simpleGLmain.cpp.

// simpleGLmain.cpp (Rob Farber)

   This wrapper demonstrates how to use the Cuda OpenGL bindings to
   dynamically modify data using a Cuda kernel and display it with opengl.

// includes, GL
#include <GL/glew.h>

// includes
#include <cuda_runtime.h>
#include <cutil_inline.h>
#include <cutil_gl_inline.h>
#include <cutil_gl_error.h>
#include <cuda_gl_interop.h>
#include <rendercheck_gl.h>

// The user must create the following routines:
void initCuda(int argc, char** argv);

// GLUT specific variables
const unsigned int window_width = 512;
const unsigned int window_height = 512;

unsigned int timer = 0; // a timer for FPS calculations

// Forward declaration of GL functionality
CUTBoolean initGL(int argc, char** argv);

// Rendering callbacks
void fpsDisplay(), display();
void keyboard(unsigned char key, int x, int y);
void mouse(int button, int state, int x, int y);
void motion(int x, int y);

// Main program
int main(int argc, char** argv)
  // Create the CUTIL timer
  cutilCheckError( cutCreateTimer( &timer));
  if (CUTFalse == initGL(argc, argv)) {
    return CUTFalse;

  initCuda(argc, argv);

  // register callbacks
  // start rendering mainloop
  // clean up
  cutilExit(argc, argv);

// Simple method to display the Frames Per Second in the window title
void computeFPS()
  static int fpsCount=0;
  static int fpsLimit=100;

  if (fpsCount == fpsLimit) {
    char fps[256];
    float ifps = 1.f / (cutGetAverageTimerValue(timer) / 1000.f);
    sprintf(fps, "Cuda GL Interop Wrapper: %3.1f fps ", ifps);  
    fpsCount = 0; 

void fpsDisplay()

float animTime = 0.0;    // time the animation has been running

// Initialize OpenGL window
CUTBoolean initGL(int argc, char **argv)
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutInitWindowSize(window_width, window_height);
  glutCreateWindow("Cuda GL Interop Demo (adapted from NVIDIA's simpleGL");
  // initialize necessary OpenGL extensions
  if (! glewIsSupported("GL_VERSION_2_0 ")) {
    fprintf(stderr, "ERROR: Support for necessary OpenGL extensions missing.");
    return CUTFalse;
  // default initialization
  glClearColor(0.0, 0.0, 0.0, 1.0);
  // viewport
  glViewport(0, 0, window_width, window_height);
  // set view matrix

  // projection
  gluPerspective(60.0, (GLfloat)window_width / (GLfloat) window_height,
	 0.10, 10.0);
  return CUTTrue;

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.