Android + OpenCL 与 Eclipse
Posted
技术标签:
【中文标题】Android + OpenCL 与 Eclipse【英文标题】:Android + OpenCL with Eclipse 【发布时间】:2015-10-26 13:14:27 【问题描述】:我正在努力让this example 在 Sony Xperia Z3 上工作。在手机上执行时,控制台会打印以下错误:
08-03 09:23:28.403: W/ResourceType(17385): Found multiple library tables,ignoring...
08-03 09:23:28.435: I/Debug(17385): OpenCL lib Loaded
08-03 09:23:28.564: I/Debug(17385): 853
08-03 09:23:28.564: I/DEBUG(17385): BEFORE runOpencl
08-03 09:23:28.567: E/art(17385): No implementation found for void com.example.inversefilter.MainActivity.initOpenCL(java.lang.String) (tried Java_com_example_inversefilter_MainActivity_initOpenCL and Java_com_example_inversefilter_MainActivity_initOpenCL__Ljava_lang_String_2)
08-03 09:23:28.568: D/androidRuntime(17385): Shutting down VM
08-03 09:23:28.570: E/AndroidRuntime(17385): FATAL EXCEPTION: main
08-03 09:23:28.570: E/AndroidRuntime(17385): Process: com.example.inversefilter, PID: 17385
08-03 09:23:28.570: E/AndroidRuntime(17385): java.lang.UnsatisfiedLinkError: No implementation found for void com.example.inversefilter.MainActivity.initOpenCL(java.lang.String) (tried Java_com_example_inversefilter_MainActivity_initOpenCL and Java_com_example_inversefilter_MainActivity_initOpenCL__Ljava_lang_String_2)
08-03 09:23:28.570: E/AndroidRuntime(17385): at com.example.inversefilter.MainActivity.initOpenCL(Native Method)
08-03 09:23:28.570: E/AndroidRuntime(17385): at com.example.inversefilter.MainActivity.onCreate(MainActivity.java:91)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.Activity.performCreate(Activity.java:5933)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2405)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.ActivityThread.access$800(ActivityThread.java:149)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1324)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.os.Handler.dispatchMessage(Handler.java:102)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.os.Looper.loop(Looper.java:211)
08-03 09:23:28.570: E/AndroidRuntime(17385): at android.app.ActivityThread.main(ActivityThread.java:5317)
08-03 09:23:28.570: E/AndroidRuntime(17385): at java.lang.reflect.Method.invoke(Native Method)
08-03 09:23:28.570: E/AndroidRuntime(17385): at java.lang.reflect.Method.invoke(Method.java:372)
08-03 09:23:28.570: E/AndroidRuntime(17385): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1016)
08-03 09:23:28.570: E/AndroidRuntime(17385): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
08-03 09:23:28.584: I/Process(17385): Sending signal. PID: 17385 SIG: 9
我认为由于错误,它是某种链接器问题或什么的。问题是,我一般是 Android 开发的新手,尤其是使用 C++ 和 OpenCL。
这是我的 Application.mk
APP_STL := stlport_static
APP_CPPFLAGS := -fexceptions
APP_OPTIM := debug
APP_ABI := armeabi-v7a
APP_PLATFORM := android-14
这是Android.mk
LOCAL_PATH := $(call my-dir)
LOCAL_PATH_EXT := $(call my-dir)/../external/
include $(CLEAR_VARS)
LOCAL_MODULE := InverseFilter
LOCAL_CFLAGS += -DANDROID_CL
LOCAL_CFLAGS += -O3 -ffast-math
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
LOCAL_SRC_FILES := InverseFilter.cpp
#LOCAL_LDFLAGS += -ljnigraphics
LOCAL_LDLIBS := -llog -ljnigraphics
LOCAL_LDLIBS += $(LOCAL_PATH)/../external/libOpenCL.so
LOCAL_ARM_MODE := arm
include $(BUILD_SHARED_LIBRARY)LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := InverseFilter
LOCAL_SRC_FILES := InverseFilter.cpp
include $(BUILD_SHARED_LIBRARY)
InverseFilter.cpp 包含以下用于 initOpenCL 的方法
void initOpenCL
(
JNIEnv* env,
jobject thisObject,
jstring kernelName,
cl_device_type required_device_type,
OpenCLObjects& openCLObjects
)
/*
* This function picks and creates all necessary OpenCL objects
* to be used at each filter iteration. The objects are:
* OpenCL platform, device, context, command queue, program,
* and kernel.
*
* Almost all of these steps need to be performed in all
* OpenCL applications before the actual compute kernel calls
* are performed.
*
* For convenience, in this application all basic OpenCL objects
* are stored in the OpenCLObjects structure,
* so, this function populates fields of this structure,
* which is passed as parameter openCLObjects.
* Consider reviewing the fields before going further.
* The structure definition is in the beginning of this file.
*/
using namespace std;
// Will be used at each effect iteration,
// and means that you haven't yet initialized
// the inputBuffer object.
openCLObjects.isInputBufferInitialized = false;
// Search for the Intel OpenCL platform.
// Platform name includes "Intel" as a substring, consider this
// method to be a recommendation for Intel OpenCL platform search.
const char* required_platform_subname = "PowerVR";
// The following variable stores return codes for all OpenCL calls.
// In the code it is used with the SAMPLE_CHECK_ERRORS macro defined
// before this function.
cl_int err = CL_SUCCESS;
/* -----------------------------------------------------------------------
* Step 1: Query for all available OpenCL platforms on the system.
* Enumerate all platforms and pick one which name has
* required_platform_subname as a sub-string.
*/
cl_uint num_of_platforms = 0;
// Get total number of the available platforms.
err = clGetPlatformIDs(0, 0, &num_of_platforms);
SAMPLE_CHECK_ERRORS(err);
LOGD("Number of available platforms: %u", num_of_platforms);
vector<cl_platform_id> platforms(num_of_platforms);
// Get IDs for all platforms.
err = clGetPlatformIDs(num_of_platforms, &platforms[0], 0);
SAMPLE_CHECK_ERRORS(err);
//cl_uint selected_platform_index = num_of_platforms;
LOGD("Platform names:");
cl_uint i = 0;
// Get the length for the i-th platform name.
size_t platform_name_length = 0;
err = clGetPlatformInfo(
platforms[i],
CL_PLATFORM_NAME,
0,
0,
&platform_name_length
);
SAMPLE_CHECK_ERRORS(err);
// Get the name itself for the i-th platform.
vector<char> platform_name(platform_name_length);
err = clGetPlatformInfo(
platforms[i],
CL_PLATFORM_NAME,
platform_name_length,
&platform_name[0],
0
);
SAMPLE_CHECK_ERRORS(err);
//selected_platform_index = 0;
openCLObjects.platform = platforms[0];
/* -----------------------------------------------------------------------
* Step 2: Create context with a device of the specified type.
* Required device type is passed as function argument required_device_type.
* Use this function to create context for any CPU or GPU OpenCL device.
*/
cl_context_properties context_props[] =
CL_CONTEXT_PLATFORM,
cl_context_properties(openCLObjects.platform),
0
;
openCLObjects.context =
clCreateContextFromType
(
context_props,
required_device_type,
0,
0,
&err
);
SAMPLE_CHECK_ERRORS(err);
/* -----------------------------------------------------------------------
* Step 3: Query for OpenCL device that was used for context creation.
*/
err = clGetContextInfo
(
openCLObjects.context,
CL_CONTEXT_DEVICES,
sizeof(openCLObjects.device),
&openCLObjects.device,
0
);
SAMPLE_CHECK_ERRORS(err);
/* -----------------------------------------------------------------------
* Step 4: Create OpenCL program from its source code.
* The file name is passed bij java.
* Convert the jstring to const char* and append the needed directory path.
*/
const char* fileName = env->GetStringUTFChars(kernelName, 0);
std::string fileDir;
fileDir.append("/data/data/com.example.inversefilter/app_execdir/");
fileDir.append(fileName);
fileDir.append(".cl");
std::string kernelSource = loadProgram(fileDir);
//std::string to const char* needed for the clCreateProgramWithSource function
const char* kernelSourceChar = kernelSource.c_str();
openCLObjects.program =
clCreateProgramWithSource
(
openCLObjects.context,
1,
&kernelSourceChar,
0,
&err
);
SAMPLE_CHECK_ERRORS(err);
/* -----------------------------------------------------------------------
* Step 5: Build the program.
* During creation a program is not built. Call the build function explicitly.
* This example utilizes the create-build sequence, still other options are applicable,
* for example, when a program consists of several parts, some of which are libraries.
* Consider using clCompileProgram and clLinkProgram as alternatives.
* Also consider looking into a dedicated chapter in the OpenCL specification
* for more information on applicable alternatives and options.
*/
err = clBuildProgram(openCLObjects.program, 0, 0, 0, 0, 0);
if(err == CL_BUILD_PROGRAM_FAILURE)
size_t log_length = 0;
err = clGetProgramBuildInfo(
openCLObjects.program,
openCLObjects.device,
CL_PROGRAM_BUILD_LOG,
0,
0,
&log_length
);
SAMPLE_CHECK_ERRORS(err);
vector<char> log(log_length);
err = clGetProgramBuildInfo(
openCLObjects.program,
openCLObjects.device,
CL_PROGRAM_BUILD_LOG,
log_length,
&log[0],
0
);
SAMPLE_CHECK_ERRORS(err);
LOGE
(
"Error happened during the build of OpenCL program.\nBuild log:%s",
&log[0]
);
return;
/* -----------------------------------------------------------------------
* Step 6: Extract kernel from the built program.
* An OpenCL program consists of kernels. Each kernel can be called (enqueued) from
* the host part of an application.
* First create a kernel to call it from the existing program.
* Creating a kernel via clCreateKernel is similar to obtaining an entry point of a specific function
* in an OpenCL program.
*/
openCLObjects.kernel = clCreateKernel(openCLObjects.program, "inverseKernel", &err);
SAMPLE_CHECK_ERRORS(err);
/* -----------------------------------------------------------------------
* Step 7: Create command queue.
* OpenCL kernels are enqueued for execution to a particular device through
* special objects called command queues. Command queue provides ordering
* of calls and other OpenCL commands.
* This sample uses a simple in-order OpenCL command queue that doesn't
* enable execution of two kernels in parallel on a target device.
*/
openCLObjects.queue =
clCreateCommandQueue
(
openCLObjects.context,
openCLObjects.device,
0, // Creating queue properties, refer to the OpenCL specification for details.
&err
);
SAMPLE_CHECK_ERRORS(err);
// -----------------------------------------------------------------------
LOGD("initOpenCL finished successfully");
extern "C" void Java_com_example_inversefilter_MainActivity_initOpenCL
(
JNIEnv* env,
jobject thisObject,
jstring kernelName
)
initOpenCL
(
env,
thisObject,
kernelName,
CL_DEVICE_TYPE_GPU,
openCLObjects
);
这部分是在 MainActivity.java 中发生错误的地方
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//outputImageView = (ImageView)findViewById(R.id.imageView1);
outputImageView = (ImageView)findViewById(R.id.imageView2);
inputBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.leopard);
Log.i("Debug", String.valueOf(inputBitmap.getWidth()));
int imageWidth = inputBitmap.getWidth();
int imageHeight = inputBitmap.getHeight();
// Two bitmap objects for the simple double-buffering scheme, where first bitmap object is rendered,
// while the second one is being updated, then vice versa.
outputBitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
Log.i("DEBUG","BEFORE runOpencl");
String kernelName = "inverse";
copyFile("inverse.cl");
initOpenCL(kernelName);
nativeInverseOpenCL(
inputBitmap,
outputBitmap
);
shutdownOpenCL();
Log.i("DEBUG","AFTER runOpencl");
Log.i("Debug", String.valueOf(outputBitmap.getWidth()));
outputImageView.setImageBitmap(outputBitmap);
非常感谢您的每一个帮助。
【问题讨论】:
【参考方案1】:您对 JNI 函数的命名有误。 查看您的错误消息:“未找到 void com.example.inversefilter.MainActivity.initOpenCL(java.lang.String) 的实现(已尝试 Java_com_example_inversefilter_MainActivity_initOpenCL 和 Java_com_example_inversefilter_MainActivity_initOpenCL__Ljava_lang_String_2)”
根据您发布的内容,我无法确定您在 JAVA 代码中定义 initOpenCL
jni 函数的位置。
假设com.example.inversefilter.jniLib.java
中存在以下定义
public static native void initOpenCL();
你的 JNI 接口应该是:
Java_com_example_inversefilter_jniLib_initOpenCL
最简单的方法是让 javah 为您生成 JNI 接口以避免任何命名错误。检查这个:javah - C Header and Stub File Generator
【讨论】:
以上是关于Android + OpenCL 与 Eclipse的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 中调用 OpenCL 函数时未定义的引用
为啥 Google 选择 RenderScript 而不是 OpenCL [关闭]