     exit(EXIT_FAILURE);
   }
 
+  if (mode==0) { ///////////////// Single-threaded CPU version /////////////////
+    for (int row=0; row<image_height; row++) {
+      for (int col=0; col<image_width; col++) {
+	  new_image[row*image_width + col] = average_3x3_CPU(image.data, col, row);
+      }
+    }    
+  }
+
   ///////////////////////////////// GPU code: //////////////////////////////////
 
-  // TODO: only come in here if mode>1
-
-  // Choose the fastest GPU (optional):
-  int devID = gpuGetMaxGflopsDeviceId();
-  checkCudaErrors( cudaSetDevice(devID) );
-  // checkCudaErrors( cudaSetDevice(0) );  // or just use the first GPU
-
-  // Prepare input and output arrays on GPU:
-  checkCudaErrors( cudaMalloc((void**)&old_image_G,image_size*sizeof(uchar)) );
-  checkCudaErrors( cudaMalloc((void**)&new_image_G,image_size*sizeof(uchar)) );
-
-  // Set GPU output to zero (optional):
-  //checkCudaErrors( cudaMemset(new_image_G, 0, image_size) );
-
-  // Copy CPU variables to GPU:
-  checkCudaErrors( cudaMemcpyToSymbol(image_height_G, &image_height, sizeof(int)) );
-  checkCudaErrors( cudaMemcpyToSymbol(image_width_G,  &image_width,  sizeof(int)) );
+  int devID;  // which GPU to use
+
+  if (mode > 1) {
+    // Choose the fastest GPU (optional):
+    devID = gpuGetMaxGflopsDeviceId();
+    checkCudaErrors( cudaSetDevice(devID) );
+    // checkCudaErrors( cudaSetDevice(0) );  // or just use the first GPU
+    
+    // Prepare input and output arrays on GPU:
+    checkCudaErrors( cudaMalloc((void**)&old_image_G,image_size*sizeof(uchar)) );
+    checkCudaErrors( cudaMalloc((void**)&new_image_G,image_size*sizeof(uchar)) );
+    
+    // Set GPU output to zero (optional):
+    //checkCudaErrors( cudaMemset(new_image_G, 0, image_size) );
+    
+    // Copy CPU variables to GPU:
+    checkCudaErrors( cudaMemcpyToSymbol(image_height_G, &image_height, sizeof(int)) );
+    checkCudaErrors( cudaMemcpyToSymbol(image_width_G,  &image_width,  sizeof(int)) );
+  }
 
   if ((mode == 2) || 
       (mode == 3) || 

  // TODO: handle borders of image, i.e. when px_x==0 and so on
}

////////////////////////////////// CPU code: ///////////////////////////////////

int main(int argc, char *argv[])
{


// These are really only global to match/simplify the pseudocode in the slides.

uchar *old_image;  // original image, CPU-side.  we don't actually use this.
uchar *new_image;  // processed image, CPU-side
int image_height;  // number of rows in image
int image_width;   // number of columns in image
