diff --git a/README.md b/README.md index c6ef0ca..362d851 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,23 @@ Please note that while node-gyp should work for compilation, it is possible that You need to update your path in order to to get AMD APP SDK's OpenCL.dll first in path resolution order. +## Android / Termux + +Install Termux (https://termux.com) + +Install Termux Packages +- pkg install clang lldb lldb-dev liblldb libuv-dev +- pkg install nodejs-lts nodejs-lts-dev + +Install OpenCL headers and libraries +- Copy libOpenCL.so to /data/data/com.termux/files/usr/lib +- Copy opencl header files to /data/data/com.termux/files/usr/include/CL + +npm install + +When running tests and examples, it may be necessary to set LD_LIBRARY_PATH +- LD_LIBRARY_PATH=/system/lib64:$LD_LIBRARY_PATH + # Usage For now you can simply require this project and call native-like functions on the global object returned. diff --git a/binding.gyp b/binding.gyp index 6a4f120..68f6b79 100644 --- a/binding.gyp +++ b/binding.gyp @@ -41,7 +41,7 @@ }, 'libraries': ['-framework OpenCL'], }], - ['OS in "linux freebsd openbsd solaris android"', { + ['OS in "linux freebsd openbsd solaris"', { 'variables' : { # AMD APP SDK 'OPENCL_SDK' : '=2.0.0", "get-pixels": ">=3.1.1", - "memwatch-next": "^0.2.10", + "memwatch-next": "git+https://github.com/jimgambale/node-memwatch#android-fpic", "nan": "^2.1.0", "pngjs2": "*" }, diff --git a/src/event.cpp b/src/event.cpp index 6833e5f..4d60d30 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -1,5 +1,9 @@ #include "event.h" #include "types.h" +#include +#include +#include + namespace opencl { @@ -184,17 +188,35 @@ NAN_METHOD(GetEventProfilingInfo) { return Nan::ThrowError(JS_STR(opencl::getExceptionMessage(CL_INVALID_VALUE))); } + +static void WorkAsync(uv_work_t *req); +static void WorkAsyncComplete(uv_work_t *req,int status); + class NoCLEventWorker : public AsyncWorker { public: - NoCLEventWorker(Callback* callback, const v8::Local &userData,const v8::Local &noCLEvent) : + uv_work_t _request; + uv_sem_t _sem_work; + + cl_int _event_command_exec_status; + +public: + NoCLEventWorker(Callback* callback, const v8::Local &userData,const v8::Local &noCLEvent) : AsyncWorker(callback) { - SaveToPersistent(kIndex, userData); - SaveToPersistent(kIndex+1,noCLEvent); + SaveToPersistent(kIndex,noCLEvent); + SaveToPersistent(kIndex+1, userData); + + _request.data = this; + uv_sem_init(&_sem_work,0); + + // kick of the worker/waiter thread + uv_queue_work(uv_default_loop(),&_request,WorkAsync,WorkAsyncComplete); + + } + + ~NoCLEventWorker() { } - - ~NoCLEventWorker() {} void CallBackIsDone(int status) { mCLCallbackStatus = status; @@ -227,25 +249,57 @@ class NoCLEventWorker : public AsyncWorker int mCLCallbackStatus = 0; }; +// called by libuv worker in separate thread +static void WorkAsync(uv_work_t *req) +{ + NoCLEventWorker *work = static_cast(req->data); + + uv_sem_wait(&work->_sem_work); +} + +// called by libuv in event loop when async function completes +static void WorkAsyncComplete(uv_work_t *req,int status) +{ + Isolate * isolate = Isolate::GetCurrent(); + + // Fix for Node 4.x - thanks to https://github.com/nwjs/blink/commit/ecda32d117aca108c44f38c8eb2cb2d0810dfdeb + v8::HandleScope handleScope(isolate); + + NoCLEventWorker *work = static_cast(req->data); + + work->CallBackIsDone(work->_event_command_exec_status); + AsyncQueueWorker(work); +} + void CL_CALLBACK notifyCB (cl_event event, cl_int event_command_exec_status, void *user_data) { - NoCLEventWorker* asyncCB = static_cast(user_data); - asyncCB->CallBackIsDone(event_command_exec_status); - AsyncQueueWorker(asyncCB); + NoCLEventWorker* work = static_cast(user_data); + + work->_event_command_exec_status = event_command_exec_status; + + uv_sem_post(&work->_sem_work); } + NAN_METHOD(SetEventCallback) { Nan::HandleScope scope; REQ_ARGS(3); + + Isolate* isolate = info.GetIsolate(); + NOCL_UNWRAP(event, NoCLEvent, info[0]); cl_int callbackStatusType = info[1]->Int32Value(); Nan::Callback *callback = new Nan::Callback(info[2].As()); - Local userData = info[3].As(); - - NoCLEventWorker* asyncCB = new NoCLEventWorker(callback,userData,info[0].As()); - - CHECK_ERR(clSetEventCallback(event->getRaw(),callbackStatusType,notifyCB,asyncCB)); - + + Local userData = v8::Undefined(isolate); + if(info.Length() >= 4 && !info[3]->IsUndefined() && !info[3]->IsNull()) { + userData = info[3].As(); + } + + NoCLEventWorker* work = new NoCLEventWorker(callback,userData,info[0].As()); + + CHECK_ERR(clSetEventCallback(event->getRaw(),callbackStatusType,notifyCB,work)); + info.GetReturnValue().Set(JS_INT(CL_SUCCESS)); } diff --git a/src/program.cpp b/src/program.cpp index ace2d00..b7e5db2 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -1,5 +1,6 @@ #include "program.h" #include "types.h" +#include #include #include "nanextension.h" @@ -156,14 +157,28 @@ NAN_METHOD(ReleaseProgram) { info.GetReturnValue().Set(JS_INT(CL_SUCCESS)); } +static void WorkAsync(uv_work_t *req); +static void WorkAsyncComplete(uv_work_t *req,int status); + + class NoCLProgramWorker : public AsyncWorker { public: - NoCLProgramWorker(Callback* callback, const v8::Local &userData,const v8::Local &noCLProgram) : + uv_work_t _request; + uv_sem_t _sem_work; + +public: + NoCLProgramWorker(Callback* callback, const v8::Local &userData,const v8::Local &noCLProgram) : AsyncWorker(callback) { - SaveToPersistent(kIndex, userData); - SaveToPersistent(kIndex+1,noCLProgram); + SaveToPersistent(kIndex,noCLProgram); + SaveToPersistent(kIndex+1, userData); + + _request.data = this; + uv_sem_init(&_sem_work,0); + + // kick of the worker/waiter thread + uv_queue_work(uv_default_loop(),&_request,WorkAsync,WorkAsyncComplete); } ~NoCLProgramWorker() {} @@ -181,7 +196,7 @@ class NoCLProgramWorker : public AsyncWorker Nan::EscapableHandleScope scope; Local argv[] = { - GetFromPersistent(kIndex), // event + GetFromPersistent(kIndex), // program GetFromPersistent(kIndex+1) // userdata }; callback->Call(2,argv); @@ -192,10 +207,31 @@ class NoCLProgramWorker : public AsyncWorker }; void CL_CALLBACK notifyPCB (cl_program prog, void *user_data) { - NoCLProgramWorker* asyncCB = static_cast(user_data); - AsyncQueueWorker(asyncCB); + NoCLProgramWorker* work = static_cast(user_data); + uv_sem_post(&work->_sem_work); +} + +// called by libuv worker in separate thread +static void WorkAsync(uv_work_t *req) +{ + NoCLProgramWorker *work = static_cast(req->data); + uv_sem_wait(&work->_sem_work); } +// called by libuv in event loop when async function completes +static void WorkAsyncComplete(uv_work_t *req,int status) +{ + Isolate * isolate = Isolate::GetCurrent(); + + // Fix for Node 4.x - thanks to https://github.com/nwjs/blink/commit/ecda32d117aca108c44f38c8eb2cb2d0810dfdeb + v8::HandleScope handleScope(isolate); + + NoCLProgramWorker *work = static_cast(req->data); + + AsyncQueueWorker(work); +} + + // extern CL_API_ENTRY cl_int CL_API_CALL // clBuildProgram(cl_program /* program */, // cl_uint /* num_devices */, diff --git a/src/svm.cpp b/src/svm.cpp index f80018c..ffced37 100644 --- a/src/svm.cpp +++ b/src/svm.cpp @@ -1,6 +1,7 @@ #include "pipe.h" #include "types.h" #include "common.h" +#include #include #include "map" #include "nanextension.h" @@ -65,14 +66,27 @@ NAN_METHOD(SVMFree) { info.GetReturnValue().Set(JS_INT(CL_SUCCESS)); } +static void WorkAsync(uv_work_t *req); +static void WorkAsyncComplete(uv_work_t *req,int status); + class NoCLSVMWorker : public AsyncWorker { +public: + uv_work_t _request; + uv_sem_t _sem_work; + public: NoCLSVMWorker(Callback* callback, const v8::Local &userData,const v8::Local &noCLCommandQueue) : AsyncWorker(callback) { - SaveToPersistent(kIndex, userData); - SaveToPersistent(kIndex+1,noCLCommandQueue); + SaveToPersistent(kIndex,noCLCommandQueue); + SaveToPersistent(kIndex+1, userData); + + _request.data = this; + uv_sem_init(&_sem_work,0); + + // kick of the worker/waiter thread + uv_queue_work(uv_default_loop(),&_request,WorkAsync,WorkAsyncComplete); } ~NoCLSVMWorker() {} @@ -102,10 +116,31 @@ class NoCLSVMWorker : public AsyncWorker // TODO should we return the svm_pointers to JS callback? void CL_CALLBACK notifySVMCB ( cl_command_queue queue, cl_uint num_svm_pointers, void *svm_pointers[], void *user_data) { - NoCLSVMWorker* asyncCB = static_cast(user_data); - AsyncQueueWorker(asyncCB); + NoCLSVMWorker* work = static_cast(user_data); + uv_sem_post(&work->_sem_work); +} + +// called by libuv worker in separate thread +static void WorkAsync(uv_work_t *req) +{ + NoCLSVMWorker *work = static_cast(req->data); + uv_sem_wait(&work->_sem_work); } +// called by libuv in event loop when async function completes +static void WorkAsyncComplete(uv_work_t *req,int status) +{ + Isolate * isolate = Isolate::GetCurrent(); + + // Fix for Node 4.x - thanks to https://github.com/nwjs/blink/commit/ecda32d117aca108c44f38c8eb2cb2d0810dfdeb + v8::HandleScope handleScope(isolate); + + NoCLSVMWorker *work = static_cast(req->data); + + AsyncQueueWorker(work); +} + + NAN_METHOD(enqueueSVMFree) { Nan::HandleScope scope; REQ_ARGS(2);