1、环境配置:
NDK
2.下载头文件:
您可以通过以下链接下载头文件:
3.声明函数并生成头文件:
public class OpenclTest {
public String testOpencl(){
return testopencl();
}
public String getplatformName(){
return getPlatformName();
}
public String getdeviceName(){
return getDeviceName();
}
public native String testopencl();
public native String getPlatformName();
public native String getDeviceName();
}
进入同级目录,使用javah命令生成头文件:
4、编写ocl.cpp文件:
//
// Created by wujs on 2017/4/11.
//
#include "CL/cl.h"
#include
#include
#include
#include
#include "topencl.h"
#include"com_pax_imagesobelfilter_OpenclTest.h"
#include
#define LOG_TAG "test"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LEN(arr) sizeof(arr) / sizeof(arr[0])
#define N 1024
#define NUM_THREAD 128
cl_uint num_device;
cl_uint num_platform;
cl_platform_id *platform;
cl_device_id *devices;
cl_int err;
cl_context context;
cl_command_queue cmdQueue;
cl_mem buffer,sum_buffer;
cl_program program ;
cl_kernel kernel;
const char* src[] = {
" __kernel void redution( \n"
" __global int *data, \n"
" __global int *output, \n"
" __local int *data_local \n"
" ) \n"
" { \n"
" int gid=get_group_id(0); \n"
" int tid=get_global_id(0); \n"
" int size=get_local_size(0); \n"
" int id=get_local_id(0); \n"
" data_local[id]=data[tid]; \n"
" barrier(CLK_LOCAL_MEM_FENCE); \n"
" for(int i=size/2;i>0;i>>=1){ \n"
" if(idNewStringUTF(result);
}
JNIEXPORT jstring JNICALL Java_com_pax_imagesobelfilter_OpenclTest_getPlatformName(JNIEnv *env , jobject thisobject)
{
char buffer[1024];
LOGD("getPlatformName start");
clGetPlatformInfo(platform[0],CL_PLATFORM_NAME,sizeof(buffer),buffer,NULL);
return env->NewStringUTF(buffer);
}
JNIEXPORT jstring JNICALL Java_com_pax_imagesobelfilter_OpenclTest_getDeviceName(JNIEnv *env , jobject thisobject)
{
char buffer[1024];
LOGD("getDeviceName start");
clGetDeviceInfo(devices[0],CL_DEVICE_NAME,sizeof(buffer),buffer,NULL);
return env->NewStringUTF(buffer);
}
void Init_OpenCL()
{
LOGD("start init OpenCL");
size_t nameLen1;
char platformName[1024];
err = clGetPlatformIDs(0, 0, &num_platform);
LOGD("err=clGetPlatformIDs");
platform=(cl_platform_id*)malloc(sizeof(cl_platform_id)*num_platform);
err = clGetPlatformIDs(num_platform, platform, NULL);
err=clGetDeviceIDs(platform[0],CL_DEVICE_TYPE_GPU,0,NULL,&num_device);
devices=(cl_device_id*)malloc(sizeof(cl_device_id)*num_device);
err=clGetDeviceIDs(platform[0],CL_DEVICE_TYPE_GPU,num_device,devices,NULL);
}
void Context_cmd()
{
context=clCreateContext(NULL,num_device,devices,NULL,NULL,&err);
cmdQueue=clCreateCommandQueue(context,devices[0],0,&err);
}
void Create_Buffer(int *data)
{
buffer=clCreateBuffer(context,CL_MEM_READ_onLY|CL_MEM_COPY_HOST_PTR,sizeof(int)*N,data,&err);
sum_buffer=clCreateBuffer(context,CL_MEM_WRITE_ONLY,sizeof(int)*num_block,0,&err);
}
void Create_program()
{
program=clCreateProgramWithSource(context, LEN(src), src, NULL, NULL);
err=clBuildProgram(program,num_device,devices,NULL,NULL,NULL);
kernel = clCreateKernel(program, "redution", NULL);
}
void Set_arg()
{
err=clSetKernelArg(kernel,0,sizeof(cl_mem),&buffer);
err=clSetKernelArg(kernel,1,sizeof(cl_mem),&sum_buffer);
err=clSetKernelArg(kernel,2,sizeof(int)*NUM_THREAD,NULL);
}
void Execution()
{
const size_t globalWorkSize[1]={N};
const size_t localWorkSize[1]={NUM_THREAD};
err=clEnqueueNDRangeKernel(cmdQueue,kernel,1,NULL,globalWorkSize,localWorkSize,0,NULL,NULL);
clFinish(cmdQueue);
}
void CopyOutResult(int*out)
{
err=clEnqueueReadBuffer(cmdQueue,sum_buffer,CL_TRUE,0,sizeof(int)*num_block,out,0,NULL,NULL);
}
5、创建.h文件和.c文件;
用于实现.so库的动态加载。 由于代码太多,这里就不全部贴出来了。 稍后会有链接。 您可以下载并根据您的实际情况进行修改。 需要修改的地方并不多。
注:以下代码是从系统加载动态库。 这里有一个问题。 如果你用的机器是N以下的话,加载是不会出错的。 但是,如果是 N 或以上,加载就会出现问题,因为它是从 N 开始的,这限制了程序加载系统私有库(NDK 中提供的库除外)。 针对这种情况,目前的解决方案是:将需要加载和依赖的库全部导入到APP中,直接从APP中加载。 可以参考这篇文章:解决N加载系统私有库的错误。
以下是.c的库加载代码:
#define LIB_OPENCL "/system/vendor/lib/libOpenCL.so"
#define LIB_GLES_MALI "/system/vendor/lib/egl/libGLES_adreno.so"
#define LIB_LLVM "/system/lib/libllvm-a3xx.so"
static void *getCLHandle(){
LOGD("get_handle");
void *res = NULL;
char* so_name="Unknown Shared library for OpenCL";
res = dlopen(LIB_OPENCL,RTLD_LAZY);
if(res != NULL){
so_name = LIB_OPENCL;
}else{
res = dlopen(LIB_GLES_MALI,RTLD_LAZY);
}
if(res != NULL){
so_name = LIB_GLES_MALI;
}else{
res = dlopen(LIB_LLVM,RTLD_LAZY);
}
if(res != NULL) {
so_name=LIB_LLVM;
} else {
LOGD("Could not open library :(\n");
}
LOGD("Loaded library name:%s\n",so_name);
return res;
}
6、编写.mk文件和.mk文件: .mk文件:
根据自己的路径修改
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_ANDROID_SDK := F:\Android\opencv-3.2.0-android-sdk\OpenCV-android-sdk
ifdef OPENCV_ANDROID_SDK
ifneq ("","$(wildcard $(OPENCV_ANDROID_SDK)/OpenCV.mk)")
include ${OPENCV_ANDROID_SDK}/OpenCV.mk
else
include ${OPENCV_ANDROID_SDK}/sdk/native/jni/OpenCV.mk
endif
else
include ../../sdk/native/jni/OpenCV.mk
endif
LOCAL_MODULE := ocl
LOCAL_CPPFLAGS += -I$(LOCAL_PATH)
LOCAL_SRC_FILES := ocl.cpp topencl.c
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
.mk 文件:
APP_CPPFLAGS := -frtti -fexceptions
#APP_STL := stlport_static
APP_STL := gnustl_static
APP_ABI := armeabi-v7a arm64-v8a
APP_PLATFORM := android-8
7. 编译:
进入jni同级目录,使用ndk-build进行编译:
,
8、程序运行结果:
上面的例程是参考这篇博文写的:#。 但这个链接是使用静态库编译的。 所以,我在这里写一篇关于手机动态加载库的文章,供大家参考。我的另一篇文章,使用T-API获取GPU信息:测试,使用的ocl封装库
代码链接:CSDN
由于sdk太大,所以我把代码中的它删除了,然后上传。 如果下载学习,必须导入并安装SDK。 apk(上面提供了下载链接,X86除外)才可以正确运行。
如果有什么问题,请在评论中提问,并尽可能解答,以便大家互相学习。