GPU Computing course - Laboration 1

Computing with GLSL




Update after the lab: Minor bugs in part 1 to 3 fixed. Part 4 is heavily revised, now firmly based on the part 3 code (thereby simpler). If you started on the old version it will work but the new version is better if you start now.

Yet another (final?) update to part 4! (100310) Sorry about the problems, but that's life with new labs in a PhD level course. (And you were warned - bugs are to be reported.) The new part 4 has some fixes and most importantly now includes a more informative shader for the last part. Parts 1-3 are also updated, but changes are minor except for one bugfix: error message for shaders are now working properly.

Please also note: If you have a working solution based on old versions, you do NOT have to update to the newer lab shells. A solution is a solution no matter where you started.



In this lab, you will be introduced to the GLSL (OpenGL Shader Language) and use it for computational purposes.

OpenGL Shader Language has a central role in computer graphics, as a cornerstone of the leading graphics library OpenGL. With recent editions of the library, more and more tasks are carried out in shaders. As shaders have become increasingly capable, these tasks have expanded into realms outside the most obvious graphics tasks. Although CUDA and OpenCL provide more control over shared memory, scattered writes and synchronizations, and hides the graphics heritage of GLSL, GLSL still is very important.

In this lab, we will spend some time on using GLSL for graphics, but focus on its use for computing, first by applying filters to images, and then for general computing on non-image data.

A brief introduction to the GLSL language is available here.



The lab is examined though a simple lab report. You should package your code (without data files or object files, please), plus comments about the result as noted below. Comments should be in a plain text file or in the body of your mail. E-mail to Ingemar.


1. Multitexturing

Goal: To get comfortable with GLSL.

Non-mandatory introduction! This is for those of you who have not used GLSL before or need to refresh your memory a bit.

We will start with "conventional" shader programming for graphics. We skip lighting calculations altogether here and focus on texturing and computation. However, this first part is a standard one just to get started.

You start from code where some textures have been loaded for you. A makefile is included.

Your task is to combine all three textures in some interesting way. You are encouraged to be creative. Note that textures can be used for other things than image data.

QUESTION: How did you combine the textures?


2. Procedural textures

Goal: To make a computationally more challenging shader with GLSL.

Let us do something of a more computational nature. "Ingemar's psychedelic teapot" is provided for you. Download it here. A makefile is included.

Modify this demo to produce a fractal image on the teapot instead. We suggest that you produce a Mandelbrot or Julia fractal. Use the texture coordinates as input to the fractal generator.

Note that shaders do not allow recursive functions. Thus, your fractal code must be iterative, and with a constant loop number.

QUESTION: How did you replace the recursion?


3. Image filtering

Goal: To learn how to perform filtering and multi-pass computing in GLSL.

Now we switch to the generic GPGPU style, with a single rectange over the entire screen. You will be using FBOs for rendering to texture. The lab shell is here: Older version.

The heart of the code is the FBO handling code, which makes ping-ponging easy. A number of FBOs are created, with the input image being loaded into fbo1. Using the call useFBO, you can set any fbo as output (first argument) or input (second two). You primarily work in the shaders and in the display() function, plus in main() for adding new shaders.

a) 2D convolution

We have "made the bed" for you fairly well in the lab shell with a small filter kernel. Expand it to a 7x7 low-pass filter (any kind you like, preferrably separable; I suggest an approximation to gaussian).

b) Separable filter kernels

Now, you must use at least two passes, applying a separable filter kernel to the image. Construct one 7x1 and one 1x7 kernel. The result should be similar to the one in 3a.

c) Performace test

Above, you made two similar or equivalent filters computed in two different ways.

Run a performance comparison on a) and b). Loop the computation sufficiently to get a stable measure. Use glFinish() to make sure that the computations finish properly. Run several tests in succession, so any startup transients don't affect the total.

You can use milli.c for a microsecond timer, as is already done in the imagefilter.c main program.

QUESTION: Do you have to make boundary checks for filters in GLSL? If not, why not?

QUESTION: What running time did you get from the two cases?


4. Working with floating-point arrays [REVISED]

Finally, we will turn to problems of a purely non-image nature. We will work on 1-dimensional arrays of numbers.

a) Simple floating-point calculations

The lab shell (process-array) uploads an array of floats to the GPU which takes the square root of all items. Experiment with data sizes and computations and inspect the running time.

Old lab files (not recommended but provided as backup):



QUESTION: What running time did for GPU vs CPU? With or without downloading the result to the CPU?

b) Sorting

You will now work on a given array of floating-point numbers, the fix-array program in the lab shell. The lab shell is similar to the previous one but includes some simple re-arranging tricks.

You should perform one of the following tasks:

QUESTION: What algorithm did you implement?