3

I am attempting to write a short application that uses OpenCL 1.2 (not for distribution, so universal access is not an issue) to do a computation. However, OpenCL is giving me a bit of trouble on Android. I have, on my computer, the libopencl.so file and the 1.2 headers from the AMD SDK. The question is: how do I properly use them?

Where in the gradle (newest version) build file do I specify this, or can someone recommend a good place for me to turn to to read up on this? Or, what do I need to understand theoretically for me to figure out on my own - what is required to properly link to the OpenCL libraries?

I've already tried the answer mentioned here: Android Studio fatal error: CL/cl.h No such file or directory

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 21
        buildToolsVersion ="22.0.1"

        defaultConfig.with {
            applicationId = "com.example.thing"
            minSdkVersion.apiLevel = 14
            targetSdkVersion.apiLevel = 14
        }
    }
    /*
     * native build settings
     */
    android.ndk {
        moduleName = "otherThing"

        ldLibs += "log"
        ldLibs += "android"
        //cFlags "~/OpenCL1-2HeaderFiles"
    }
    android.buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles  += file('proguard-rules.txt')
        }
    }

    android.productFlavors {
        create("arm") {
            ndk.abiFilters += "armeabi"
        }
        create("arm7") {
            ndk.abiFilters += "armeabi-v7a"
        }
        create("arm8") {
            ndk.abiFilters += "arm64-v8a"
        }
        create("x86") {
            ndk.abiFilters += "x86"
        }
        create("x86-64") {
            ndk.abiFilters += "x86_64"
        }
        create("mips") {
            ndk.abiFilters += "mips"
        }
        create("mips-64") {
            ndk.abiFilters += "mips64"
        }
        create("all")
    }
}

Thanks

Community
  • 1
  • 1
markymark
  • 93
  • 1
  • 7
  • Since Android and OpenCL are not really good friend (thanks google for prefering RenderScript). I recommend you use a non-library implementation, using CLEW as base, and dynamic loading the .lib from the device. In some devices the OpenCL is inside other libraries like libGLES_MALI.so, so you need to load those instead. – DarkZeros Jul 24 '15 at 14:55

3 Answers3

3

It is quite complicated process. I will try to keep it concise.

  1. To run your app on Android, libopencl.so from AMD will not work. The OpenCL library must be compatible with your device. For Android armv7 device, you need a OpenCL library provided by the chip vendor, and compiled with armv7 toolchain. To run on Intel Atom device, you need the library to be provided by the chip vendor and was compiled targeting to x86_32 arch.

Basically, for your question, You have two ways to go:

[Method 1] grab the libOpenCL.so or libGLES_mali.so, or libPVROCL.so from devices you have. The above lib names correspond to Adreno, Mali and PowerVR GPUs. Use those libraries to compile your code.

[Method 2] In your native code, open the OpenCL library using dlopen, then using dlsym to map the clBlaBla APIs to your own name. For example, you can map clGetDeviceInfo to myCLGetDeviceInfo. Then, in your own native code, you can call myClGetDeviceInfo instead. This way requires you know the path to the opencl library on your devices. For example, on Adreno GPUs, the location will be /system/vendor/lib/libOpenCL.so. For more details, read another post. Does Android support OpenCL?

Method 2 is more general and elegant. Method 1 is simpler, and quicker if you clearly know what devices your app will run on. For example, if you clearly know your app is only for testing on adreno gpus, then you can simply grab libOpenCL.so from your test device. Then use it to link your app. This link shows how to do this, and provides an sample code. You can start from there.

In terms of using Android studio. I can only comment this: if you understand the requirement of compiling an OpenCL app on Android. Compiling using Android studio or directly using ndk-build have no difference. The syntax can be one-to-one mapped from one to another.

For my personal experience, I wrote a lot of Android.mk files, and I am getting used to it. So even if now I use Android Studio to develop. The method in the article you linked is actually correct.

However, I still use ndk-build to compile my native code, as usual. That way, I can have full control on what happened there, and I feel more comfortable. Once I got the .so native library, I put it into the jniLibs folder under src/main (your folder structure could be different). jniLibs is the default folder where the Android studio will locate the native libraries. You can also specify your own folder in the gradle script (tons of articles online, search gradle ndk). Of course, all the above operations are done by a script (ndk-build, copy the library to some folder). Once I have all these, I build the app using Android studio. Typically, you wont debug the JAVA code and change native code at the same time, so doing the above is totally OK and quite comfortable. If you want to automate all these, you can ask the gradle to launch the ndk build script you wrote before it builds the app. Or you can ask the gradle to run ndk-build command the way you like (this is actually used by a lot of developer).

Hope this is helpful. Any further discussion is welcome.

Community
  • 1
  • 1
Robert Wang
  • 1,161
  • 9
  • 15
  • Thank you so much for your response, Robert! I needed to get something working, so I abandoned Android Studio in favor of Eclipse. – markymark Aug 23 '15 at 12:44
  • When using method 2, how to call the [atan2](https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/atan.html) function ? – RonTLV Sep 13 '17 at 17:22
  • The atan2 function is kernel function, which belongs to the OpenCL C language. The methods discussed above are related to the host functions (OpenCL API functions). No matter which methods you use, if the devices support OpenCL, atan2 func should be there. – Robert Wang Oct 01 '17 at 09:15
3

Thank you so much for your response, Robert! I needed to get something working, so what I ended up doing was going through the device that it's installed on by checking through

static const char *default_so_paths[] = { // Android
                                            "/system/lib/libOpenCL.so", "/system/vendor/lib/libOpenCL.so",
                                            "/system/vendor/lib/egl/libGLES_mali.so",
                                            "/system/vendor/lib/libPVROCL.so",
                                            "/data/data/org.pocl.libs/files/lib/libpocl.so",
                                          // Linux
                                            "/usr/lib/libOpenCL.so",            "/usr/local/lib/libOpenCL.so",
                                            "/usr/local/lib/libpocl.so",
                                            "/usr/lib64/libOpenCL.so", "/usr/lib32/libOpenCL.so",
                                            "libOpenCL.so"
                                          };

And then mapping the APIs, which I guess I must have seen how to do sometime ago.

I've finally got things working, but I wanted to thank you, for both this comprehensive response and, well, most of your responses on this forum regarding this topic. They've all been very helpful.

markymark
  • 93
  • 1
  • 7
  • 1
    This is actually a much nicer way of OpenCL programming for Android. Happy to see you make it work this way. This actually allows your program to be compiled/linked much easier especially if you wan to support as many as GPUs. – Robert Wang Oct 04 '15 at 09:42
2
Caused by: java.lang.IllegalArgumentException: Internal error: Failed to apply delegate: Can not open OpenCL library on this device - dlopen failed: library "libOpenCL.so" not found
    Falling back to OpenGL
    TfLiteGpuDelegate Init: No shader implementation for reduce_maximum
    TfLiteGpuDelegate Prepare: delegate is not initialized

For this error it can be fixed by writing in application AndroidManifest.xml :::
        <uses-native-library
        android:name="libOpenCL.so"
        android:required="false" />