Technical News from The Portland Group

Creating an OpenCL-enabled Android App with PGCL

PGCL is an OpenCL compiler framework for ARM processor-based Systems-on-Chip (SoCs). It allows developers to create applications that run in parallel across multiple ARM CPU cores with NEON/SIMD extensions as an OpenCL compute device. PGCL is designed to be extensible, to allow for support of other types of OpenCL compute devices in the future. It gives ARM developers an avenue to create applications that are multi-core enabled, inherently scalable, and forward-portable to the coming accelerator-enabled mobile platforms.

PGCL can be used in combination with the Eclipse IDE and Dalvik (the Android Java environment) to create Android Apps in which compute-intensive portions of the App are accelerated on multiple ARM cores using OpenCL kernel functions. Most Android Apps are written in Java using the Android SDK (Software Development Kit), which allows some features to be written in the C language and made available within a Java App using the JNI (Java Native Interface). To accelerate portions of an App using PGCL, you simply write native C code that performs calls to OpenCL API routines and is dynamically linked with OpenCL device code compiled using the PGCL driver. The sections which follow describe how to create an App using this process.

Initializing your Android Development Environment for Use with PGCL

It is assumed here that you are already familiar with the use of Eclipse to create Android Apps, and that you have already set up an Android Java development environment on a Linux/x86 host as described on the Android Developer website. For this example, we will be using Android Platform 2.3.3 (Gingerbread). In addition, you must install the Android NDK as described on the Android Developer website.

Once you have the Java development kit and NDK installed, add the Android NDK directory to your PATH environment variable in a command-level shell. Make sure the correct connection via adb is established from Eclipse to your target Android device. Once this is accomplished, ensure that the installed location of PGCL is also included in your PATH environment variable, then launch the Eclipse IDE from your command shell.

Importing PGI's JavaLibOpenCL into your Eclipse Workspace

Most Android Apps are designed as Activities. Included with the PGCL distribution is the Android Java file OpenCLActivity.java that defines the OpenCLActivity class. This file can be found in the directory $PGI/androidarm/EXAMPLES/Dalvik/JavaLibOpenCL/src/com/pgroup/lib . The usage model is that an Android Activity can extend the OpenCLActivity class to use native functions that include OpenCL compute kernels. Follow these steps to import the OpenCLActivity class into your Eclipse workspace:

  1. From the Eclipse menu, select File->Import

    Eclipse Import command

  2. In the Import dialog, choose General->Existing Projects into Workspace, then click the Next > button.

    Eclipse select project command

  3. In the Import Project dialog, choose “Select root directory”, browse to $PGI/androidarm/EXAMPLES/Dalvik/JavaLibOpenCL , and then click "OK."

    You should choose the "Copy projects into workspace" option to avoid working in the original PGCL install directory.

    The Projects list should now be populated with a project named JavaLibOpenCL.

    Eclipse Import project

  4. Click "Finish". This should import into your Eclipse Workspace a new project named JavaLibOpenCL. This project includes Java sources for the OpenCLActivity class

    Eclipse Workspace

    Now you can incorporate the OpenCLActivity class to build an Android Activity that uses OpenCL.

Creating an Android Activity that uses OpenCL

To create an Android Activity that uses the OpenCLActivity class, the following steps are required:

  1. In Eclipse, create a new project using the menu: File->New-> Project.

  2. Select Android Project in the New Project Wizard, then click Next >.

  3. Choose the Name of your Project; for instance OclApp , and click Next>.

  4. In the Select Build Target dialog, select Android 2.3.3, then click Next>.

    If Android 2.3.3 is missing then you have not set up Android with the 2.3.3 platform. You must do so to use PGCL 12.7. Future versions of PGCL will support Android 4.x (ICS) platforms.

  5. Specify a package name like com.pgroup.samples and set Minimum SDK to the value 10 (Android 2.3.3). Then click Finish.

    A new project named OclApp should have been created in your Workspace. An OclAppActivity class should also have been created.

  6. In the package explorer, right click on OclApp and select Properties from the menu.

  7. In the Properties for OclApp dialog, select Android, and add library JavaLibOpenCL into the Library list.

    An OclAppActivity class should have been generated and its code should look as follows:

    package com.pgroup.samples;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    public class OclAppActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        }
    }
    

    To enable use of OpenCL in native code, this activity can be modified so that it extends OpenCLActivity instead of the Activity class. The modified code should look as follows:

    package com.pgroup.samples;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    public class OclAppActivity extends OpenCLActivity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        }
    }

    You now have an Android Activity that can instantiate native C host code that uses OpenCL compute kernels compiled using PGCL.

Implementing SURF as an OpenCL-enabled Android App

The PGCL distribution includes an example Android App named NDKOclSurf. This example includes an OpenCL implementation of the Speed Up Robust Feature detector (SURF) algorithm. SURF is a robust image detector and descriptor, first presented by Herbert Bay et al. in 2006, that can be used in computer vision tasks like object recognition or 3D reconstruction. SURF is based on sums of 2D Haar wavelet responses and makes an efficient use of integral images. While the PGCL implementation is derived from AMD's open source implementation named CLSURF, there are several important differences:

Importing PGCL NDKOclSurf into your Eclipse Workspace

Follow these steps to import the PGCL SURF example into your Eclipse workspace

  1. From the Eclipse menu, select File->Import…

    Eclipse Import command

  2. Expand the General Folder of the Import dialog, choose Existing Projects into Workspace, then click Next >.

    Eclipse Import command

  3. In the Import Project dialog, click Select root directory, browse to $PGI/androidarm/EXAMPLES/Dalvik/NDKOclSurf, and then click OK.

    You should choose the Copy projects into workspace option to avoid working in the original PGCL install directory.

    The Projects list should now be populated with a project named NDKOclSurf.

    Eclipse Import command

  4. Click Finish.

    This should import into your Eclipse Workspace a new project named NDKOclSurf. This project includes Java sources for the NDKOclSurfActivity class.

Building the PGCL SURF example

Compiling your application requires the following three steps:

  1. Build the OpenCL kernels code. Open a terminal window and execute following commands:

    % cd <your_workspace_dir>/NDKOclSurf/jni/kernel
    % make
    

    Binary images named libXXX.so should have been created in the directory <your_workspace_dir>/NDKOclSurf/jni/kernel/libs/armeabi-v7a.

  2. Build the OpenCL host code. Verify the Android NDK has been installed on your workstation and access to the ndk-build command is specified in your path environment variable. Then, in a terminal window, execute the following commands:

    % cd <your_workspace_dir>/NDKOclSurf 
    % ndk-build
    

    A binary image named libsurfimage.so should have been created and installed in the directory <your_workspace_dir>/NDKOclSurf/libs/armeabi-v7a. The ndk-build command also installs previously created kernel binaries, libXXX.so files, in the same directory.

  3. Rebuild the Android App. In Eclipse, highlight NDKOclSurf in the package explorer, and from the menu, select Project > Clean...

    Eclipse Import command

    The Clean Dialog should appear. Select NDKOclSurf as the project to clean, and make sure it is rebuilt by checking Start a build immediately as illustrated here:

    Eclipse Import command

    When you click OK, your Android App will be rebuilt. It is important to respect the build order described previously, since there are implicit dependencies between the OpenCL kernels binaries, the OpenCL host code, and an Android App. Since the Android App Eclipse build process doesn't handle native code, and the native code build process (ndk-build) doesn't handle building of OpenCL kernels, it is important to respect the following build rules:

    • Any change to OpenCL kernel code (.cl files) require build steps 1, 2, and 3 to be performed for your application to take advantage of those changes.

    • Any change to OpenCL host code (.c, .cpp) requires build steps 2 and 3 to be performed for your application to take advantage of those changes.

    • Any change to Android App code (.java) should be automatically handled by Eclipse.

    Once your application has been built, you can use the Eclipse Debug Perspective to install and launch the OpenCL-enabled App on your Android device. The PGCL SURF App is performing a loop that displays Points Of Interest detected by the SURF algorithm. For each loop iteration, parameters used by SURF are changed. Thus the number of Points Of Interest varies. While this information is not used, so-called SURF descriptors are also computed for each Point Of Interest. When launched on an Android device, the screen should look as follows after a SURF loop iteration:

    Eclipse Import command

Conclusion

In this article, we have shown step-by-step how to incorporate an Activity into an Android App that enables compute-intensive portions of the App to be accelerated on multiple ARM cores with NEON using OpenCL. As an example, we used an OpenCL implementation of the SURF algorithm with the compute kernels modified from original GPU versions into a form more suitable for execution on a multi-core CPU. We did not delve into the OpenCL kernel source to examine the types of modifications made in the development of this App, many of which are generally applicable to porting or development of OpenCL kernels for execution on a CPU. In a future article, we will focus in on the kernel source as an example to display some coding guidelines and tips for development of efficient OpenCL kernels using PGCL on multi-core ARM SoCs.