Cogs and Levers A blog full of technical stuff

Setup Debian for OpenCL Development

Introduction

OpenCL (or Open Computing Language) is a framework that allows you to write code across different connected devices to your computer. Code that you write can execute on CPUs, GPUs, DPSs amongst other pieces of hardware. The framework itself is a standard that puts the focus on running your code across these devices but also emphasises parallel computing.

Today’s post will just be on getting your development environment setup on Debian Wheezy to start writing some code.

Installation

The installation process is pretty straight forward, but there are some choices in libraries. The major vendors (Intel, NVIDIA and AMD) all have development libraries that are installable from Debian’s package repository. There’s plenty of banter on the internet as to who’s is better for what purpose.

First off, we need to install the header files we’ll use to create OpenCL programs.

$ sudo apt-get install opencl-headers

This has now put all of the development headers in place for you to compile some code.

$ ls -al /usr/include/CL
total 1060
drwxr-xr-x  2 root root   4096 Nov 25 22:51 .
drwxr-xr-x 56 root root   4096 Nov 25 22:51 ..
-rw-r--r--  1 root root   4859 Nov 15  2011 cl_d3d10.h
-rw-r--r--  1 root root   4853 Apr 18  2012 cl_d3d11.h
-rw-r--r--  1 root root   5157 Apr 18  2012 cl_dx9_media_sharing.h
-rw-r--r--  1 root root   9951 Nov 15  2011 cl_ext.h
-rw-r--r--  1 root root   2630 Nov 17  2011 cl_gl_ext.h
-rw-r--r--  1 root root   7429 Nov 15  2011 cl_gl.h
-rw-r--r--  1 root root  62888 Nov 17  2011 cl.h
-rw-r--r--  1 root root 915453 Feb  4  2012 cl.hpp
-rw-r--r--  1 root root  38164 Nov 17  2011 cl_platform.h
-rw-r--r--  1 root root   1754 Nov 15  2011 opencl.h

Secondly, we need to make a choice in what library we’ll use:

The amd-opencl-dev package will install AMD’s implementation, which you can read up on here. NVIDIA’s package is installable through the nvidia-opencl-dev package which you can read up on here. Finally, Intel’s implementation is available through the beignet-dev package and you can read up on their implementation here.

I went with AMD’s.

$ sudo apt-get install amd-opencl-dev

From here, it’s time to write some code. I’ll have some more blog posts on the way which will be walk-throughs for your first applications.

Gouraud Shaing with Scan Line Polygons

Introduction

In my previous post, we went through the basics of rasterising polygons on screen by use of horizontal lines. To sum up, we interpolated values along each edge of the polygon, collecting minimum and maximums for each y-axis instance.

Today, we’re going to define a colour value for each point on the polygon and interpolate the colours along each edge. This is the technique employed to draw polygons that are Gouraud shaded.

The Code

The structure of this is very similar to drawing a single colour block polygon. For a solid colour polygon, we interpolated the x values over the length of the y values. We’ll now employ this same interpolation technique over the red, green, blue and alpha channels of each colour defined for each polygon point. Here’s the scanline function.

var scanline_g = function(p1, p2, miny, edges) {

   // if the y values aren't y1 < y2, flip them
   // this will also flip the colour components
   if (p2.y < p1.y) {
      var p = p1;
      p1 = p2;
      p2 = p;
   }

   // initialize our counters for the x-axis, r, g, b and a colour components
   var x = p1.x;
   var r = p1.r, g = p1.g, b = p1.b, a = p1.a;
   
   // calculate the deltas that we'll use to interpolate along the length of
   // the y-axis here (y2 - y1)
   var yLen = p2.y - p1.y;
   var dx = (p2.x - p1.x) / yLen;
   var dr = (p2.r - p1.r) / yLen;
   var dg = (p2.g - p1.g) / yLen;
   var db = (p2.b - p1.b) / yLen;
   var da = (p2.a - p1.a) / yLen;
   
   // find our starting array index
   var ofs = p1.y - miny;

   // enumerate each point on the y axis
   for (var y = p1.y; y <= p2.y; y ++) {

      // test if we have a new minimum, and if so save it
      if (edges[ofs].min.x > x) {
         edges[ofs].min.x = Math.floor(x);
         edges[ofs].min.r = Math.floor(r);
         edges[ofs].min.g = Math.floor(g);
         edges[ofs].min.b = Math.floor(b);
         edges[ofs].min.a = Math.floor(a);
      }

      // test if we have a new maximum, and if so save it
      if (edges[ofs].max.x < x) {
         edges[ofs].max.x = Math.floor(x);
         edges[ofs].max.r = Math.floor(r);
         edges[ofs].max.g = Math.floor(g);
         edges[ofs].max.b = Math.floor(b);
         edges[ofs].max.a = Math.floor(a);
      }

      // move our interpolators along their respective paths
      x += dx;
      r += dr;
      g += dg;
      b += db;
      a += da;

      // move to the next array offset
      ofs ++;

   }


};

An immediate code restructure difference here from the first tutorial, is I’m now passing an actual point object through as opposed to each component of each point being a function parameter. This is just to clean up the interface of these functions. We’re creating differentials not only for x now but also the r, g, b and a components. These will form the start and ending colours for each horizontal line that we’ll draw. We still have extra interpolation to do once we’re in the horizontal line draw function as well. Here it is.

var hline_g = function(x1, x2, y, w, c1, c2, buffer) {

   // calculate the starting offset to draw at
   var ofs = (x1 + y * w) * 4;
   // calculate the length of the line
   var lineLength = x2 - x1;
   
   // calculate the deltas for the red, green, blue and alpha channels
   var dr = (c2.r - c1.r) / lineLength;
   var dg = (c2.g - c1.g) / lineLength;
   var db = (c2.b - c1.b) / lineLength;
   var da = (c2.a - c1.a) / lineLength;
   
   // initialize our counters
   var r = c1.r, g = c1.g, b = c1.b, a = c1.a;

   // interpolate every position on the x axis
   for (var x = x1; x <= x2; x ++) {
     
      // draw this coloured pixel
      buffer[ofs] = Math.floor(r);
      buffer[ofs + 1] = Math.floor(g);
      buffer[ofs + 2] = Math.floor(b);
      buffer[ofs + 3] = Math.floor(g);

      // move the interpolators on
      r += dr; g += dg; b += db; a += da;
      
      // move to the next pixrl
      ofs += 4;
   }

};

Again, more interpolation of colour components. This is what will give us a smooth shading effect over the polygon. Finally, the actual polygon function is a piece of cake. It just gets a little more complex as we have to send in colours for each point defined.

var polygon_g = function(p1, p2, p3, p4, w, buffer) {
   // work out the minimum and maximum y values for the polygon
   var miny = p1.y, maxy = p1.y;

   if (p2.y > maxy) maxy = p2.y;
   if (p2.y < miny) miny = p2.y;
   if (p3.y > maxy) maxy = p3.y;
   if (p3.y < miny) miny = p3.y;
   if (p4.y > maxy) maxy = p4.y;
   if (p4.y < miny) miny = p4.y;

   var h = maxy - miny;
   var edges = new Array();

   // create the edge storage so we can keep track of minimum x, maximum x
   // and corresponding r, g, b, a components
   for (var i = 0; i <= h; i ++) {
      edges.push({

         min: {
            x: 1000000,
            r: 0,
            g: 0,
            b: 0,
            a: 0
         },

         max: {
            x: -1000000,
            r: 0,
            g: 0,
            b: 0,
            a: 0
         }

      });
   }

   // perform the line scans on each polygon egde
   scanline_g(p1, p2, miny, edges);
   scanline_g(p2, p3, miny, edges);
   scanline_g(p3, p4, miny, edges);
   scanline_g(p4, p1, miny, edges);

   // enumerate over all of the edge items
   for (var i = 0; i < edges.length; i ++) {
      // get the start and finish colour
      c1 = { r: edges[i].min.r, g: edges[i].min.g, b: edges[i].min.b, a: edges[i].min.a };
      c2 = { r: edges[i].max.r, g: edges[i].max.g, b: edges[i].max.b, a: edges[i].max.a };

      // draw the line
      hline_g(edges[i].min.x, edges[i].max.x, i + miny, w, c1, c2, buffer);
   }
};

Aside from the interface changing (just to clean it up a bit) and managing r, g, b and a components - this hasn’t really changed from the block colour version. If you setup this polygon draw in a render loop, you should end up with something like this: Shaded polys

Smooth.

Scanline based filled Polygons

Introduction<

In a previous post I laid down some foundation code to get access to the pixel buffer when in context of a HTML canvas. Good for those who have experience writing graphics code directly against the video buffer - it almost feels like you’re writing to 0xA000 :-)<

Today’s post will focus on drawing polygons to the screen using scan lines.

Scan lines

The whole idea here is that a polygon can be represented on screen as a series of horizontal lines. Take the following picture for example. You can see the red and blue horizontal lines making up the filling of the polygon.

Scanlines

So, to define this all we do is take note of the minimum and maximum x values for every y-axis instance that there is a line on. We run through the array of values drawing horizontal lines at each instance, and then we have a polygon on screen - pretty easy.

Code

First of all, we’ll define our drawing primitive for a horizontal line.

var hline_c = function(x1, x2, y, w, r, g, b, a, buffer) {
   // calculate the offset into the buffer
   var ofs = (x1 + y * w) * 4;

   // draw all of the pixels
   for (var x = x1; x <= x2; x ++) {
      buffer[ofs] = r;
      buffer[ofs + 1] = g;
      buffer[ofs + 2] = b;
      buffer[ofs + 3] = a;

      // move onto the next pixel
      ofs += 4;
   }

};

We pass in the two x (x1 and x2) values for the line to go between, the y value for the line to sit on. To help with the offset calculation we also pass in the width w to correctly calculate the pitch. Finally the colour components and buffer to draw to are passed in. Setting this code up in a run loop, you end up with something like this:

Poly

Yep, there’s lots of horizontal lines. Referring to our horizontal line diagram above, we still need a way to walk the edges of the polygon so that we can get the minimum and maximum x values to start drawing. Because our basic unit is the pixel (considering we’re rasterising to a pixelated display), we can easily calculate the gradient of the line that we need by:

(change in x) / (change in y)

For a line given by (x1, y1) - (x2, y2), this translates into:
(x2 - x1) / (y2 - y1)

Taken out of context of maths, this just says to us: we want to walk from x1 to x2 using (y2 - y1) steps.

var scanline_c = function(x1, y1, x2, y2, miny, edges) {

   // flip the values if need be
   if (y1 > y2) {
      var y = y1;
      y1 = y2;
      y2 = y;

      var x = x1;
      x1 = x2;
      x2 = x;
   }

   // start at the start
   var x = x1;
   // change in x over change in y will give us the gradient
   var dx = (x2 - x1) / (y2 - y1);
   // the offset the start writing at (into the array)
   var ofs = y1 - miny;

   // cover all y co-ordinates in the line
   for (var y = y1; y <= y2; y ++) {
     
      // check if we've gone over/under the max/min
      if (edges[ofs].minx > x) edges[ofs].minx = x;
      if (edges[ofs].maxx < x) edges[ofs].maxx = x;

      // move along the gradient
      x += dx;
      // move along the buffer
      ofs ++;

   }

};

From the code above, we treat x1, y1 as the starting point and x2, y2 as the ending point. Our for-loop is biased in the positive direction, so it’s important for us to flip the values if they come in inverted. The edges array that’s passed in is prepared by the caller of this function. It’s initialized with very unreasonable minimum and maximum values. We than run over all 4 polygon edges

(x1, y1) -> (x2, y2)
(x2, y2) -> (x3, y3)
(x3, y3) -> (x4, y4)
(x4, y4) -> (x1, y1)

At the end of this process, edges is full of minimum/maximum values ready for drawing. Here’s the code for the polygon.

var polygon_c = function(x1, y1, x2, y2, x3, y3, x4, y4, w, r, g, b, a, buffer) {
   // work out the minimum and maximum y values
   var miny = y1, maxy = y1;

   if (y2 > maxy) maxy = y2;
   if (y2 < miny) miny = y2;
   if (y3 > maxy) maxy = y3;
   if (y3 < miny) miny = y3;
   if (y4 > maxy) maxy = y4;
   if (y4 < miny) miny = y4;

   // the height will determine the size of our edges array
   var h = maxy - miny;
   var edges = new Array();

   // build the array with unreasonable limits
   for (var i = 0; i <= h; i ++) {
      edges.push({
         minx:  1000000,
         maxx: -1000000
      });
   }

   // process each line in the polygon
   scanline_c(x1, y1, x2, y2, miny, edges);
   scanline_c(x2, y2, x3, y3, miny, edges);
   scanline_c(x3, y3, x4, y4, miny, edges);
   scanline_c(x4, y4, x1, y1, miny, edges);

   // draw each horizontal line
   for (var i = 0; i < edges.length; i ++) {
      hline_c(
         Math.floor(edges[i].minx),
         Math.floor(edges[i].maxx),
         Math.floor(i + miny),
         w, r, g, b, a, buffer);
   }
};

This really is just putting all the pieces together. The building of the edges array is important - as is using the y co-ordinate (adjusted back to zero by proxy of the minimum y value) as an array index. Once you’ve got this setup in a random position & colour loop, you’ll end up with something like this:

Polys

mmmm… Tasty.

Purging all of the data within Solr

During the test phases of getting your software setup, you’ll find it useful to completely toast what ever data you’ve already indexed to start fresh. This is as simple as issuing a delete query with open criteria *.*. The full query should translate to

<delete><query>*.*</query></delete>

As a URL it’ll look like this:

http://[your solr server]:8080/solr/update?stream.body=%3Cdelete%3E%3Cquery%3E*:*%3C/query%3E%3C/delete%3E&commit=true

Note that there is a commit at the end of this URL which will perform the delete and commit the result all in the one invocation.

Pixel Access to the Canvas with Javascript

Introduction

Gaining pixel-level access using the HTML canvas opens up some possibilities for some frame-buffer style rasterisation. Today’s post will focus on the code required to get you access to this array. Here’s the code on how to get started:

// create the canvas object
var canvas = document.createElement("canvas");

// maximise the canvas to stretch over the window
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// get the 2d drawing context for 
var cxt = canvas.getContext("2d");
// get the image data
var imageData = cxt.createImageData(width, height);

// save off the dimensions for later use
var width = canvas.width;
var height = canvas.height;

// get the canvas on the page
document.body.appendChild(canvas);

First of all, we programmatically create our canvas object using document.createElement. Using the inner dimensions of the window, we can then set the canvas’ size. Of course this can be custom set to the dimensions you require - I just like to take over the whole window! Using the canvas object, we then pull out the drawing context with getContext. The next part, using createImageData we then get a reference to the frame-buffer to draw to. This gives us read/write access to the canvas through an array. Finally, we’ll take note of the width and height (this will come in handy later) and then pop the canvas onto the page.

Frame-buffer structure

So, I say “frame-buffer” - but it’s just an array. It’s quite nicely laid out such that pixels start at every 4 elements within the array. The first element being the red component, second is green, third is blue and the fourth is the alpha. Calculating an offset into the array is a piece of cake. For example, take the following piece of code which will allow you to set a single pixel on the frame-buffer.

var setPixel = function(x, y, r, g, b, a, buffer) {
  // calculate the start of the pixel
  var offset = ((y * width) + x) * 4;
  
  // set the components
  buffer[offset] = r;
  buffer[offset] = g;
  buffer[offset] = b;
  buffer[offset] = a;
};

The main part to focus on here is the calculation of the offset. Above, I said it was important to take note of the dimensions - we’re only using the width here. This is pretty straight forward calculation of an offset within a linear data segment with Cartesian co-ordinates.

Flip out!

Now that we’ve drawn all of the data to the image buffer (frame-buffer), we need a way to get it back onto our canvas. This is simply done using putImageData.

cxt.putImageData(imageData, 0, 0);

That’s it for now.