diff options
author | Chad Austin <chad@imvu.com> | 2013-05-03 18:20:26 -0700 |
---|---|---|
committer | Chad Austin <chad@imvu.com> | 2013-05-17 12:56:48 -0700 |
commit | fd8cbaa853ec9ea1f2c0c689e1729126c52368e4 (patch) | |
tree | 5359cad8a12b53f4d74dcd129945c6d08825a3c8 | |
parent | 7f83ab2926947fda7181a7e67e76425f02da19c4 (diff) |
Add support for (fast?) memory_view objects. If C++ passes a memory_view to JS, it gets converted into a typed array object on the other side. Intended for WebGL.
-rw-r--r-- | src/embind/embind.js | 30 | ||||
-rw-r--r-- | src/embind/emval.js | 17 | ||||
-rw-r--r-- | system/include/emscripten/bind.h | 4 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 1 | ||||
-rw-r--r-- | system/include/emscripten/wire.h | 73 | ||||
-rw-r--r-- | system/lib/embind/bind.cpp | 1 | ||||
-rw-r--r-- | tests/embind/embind.test.js | 22 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 19 |
8 files changed, 159 insertions, 8 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js index dfe4c014..d1508269 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -131,6 +131,7 @@ function extendError(baseErrorType, errorName) { // from https://github.com/imvu/imvujs/blob/master/src/function.js function createNamedFunction(name, body) { + name = makeLegalFunctionName(name); /*jshint evil:true*/ return new Function( "body", @@ -453,6 +454,33 @@ function __embind_register_emval(rawType, name) { }); } +function __embind_register_memory_view(rawType, name) { + var typeMapping = [ + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + ]; + + name = readLatin1String(name); + registerType(rawType, { + name: name, + 'fromWireType': function(handle) { + var type = HEAP32[handle >> 2]; + var size = HEAP32[(handle >> 2) + 1]; // in elements + var data = HEAP32[(handle >> 2) + 2]; // byte offset into emscripten heap + _free(handle); + var TA = typeMapping[type]; + return new TA(HEAP8.buffer, data, size); + }, + destructorFunction: function(ptr) { _free(ptr); }, + }); +} + function runDestructors(destructors) { while (destructors.length) { var ptr = destructors.pop(); @@ -681,7 +709,7 @@ function __embind_finalize_tuple(rawTupleType) { }, 'toWireType': function(destructors, o) { if (elementsLength !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); + throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length); } var ptr = rawConstructor(); for (var i = 0; i < elementsLength; ++i) { diff --git a/src/embind/emval.js b/src/embind/emval.js index bfce63b6..96024269 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -1,5 +1,6 @@ /*global Module, Runtime*/ /*global HEAP32*/ +/*global createNamedFunction*/ /*global readLatin1String, writeStringToMemory*/ /*global requireRegisteredType, throwBindingError*/ @@ -192,11 +193,14 @@ function parseParameters(argCount, argTypes, argWireTypes) { function __emval_call(handle, argCount, argTypes) { requireHandle(handle); + var types = lookupTypes(argCount, argTypes); + + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = types[i].fromWireType(arguments[3 + i]); + } + var fn = _emval_handle_array[handle].value; - var args = parseParameters( - argCount, - argTypes, - Array.prototype.slice.call(arguments, 3)); var rv = fn.apply(undefined, args); return __emval_register(rv); } @@ -214,7 +218,8 @@ function lookupTypes(argCount, argTypes, argWireTypes) { function __emval_get_method_caller(argCount, argTypes) { var types = lookupTypes(argCount, argTypes); - return Runtime.addFunction(function(handle, name) { + var signatureName = types[0].name + "_$" + types.slice(1).map(function(t){return t.name;}).join("_") + "$"; + return Runtime.addFunction(createNamedFunction(signatureName, function(handle, name) { requireHandle(handle); name = getStringOrSymbol(name); @@ -225,7 +230,7 @@ function __emval_get_method_caller(argCount, argTypes) { var obj = _emval_handle_array[handle].value; return types[0].toWireType([], obj[name].apply(obj, args)); - }); + })); } function __emval_has_function(handle, name) { diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index d6d4f2c5..4be50c9d 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -59,6 +59,10 @@ namespace emscripten { TYPEID emvalType, const char* name); + void _embind_register_memory_view( + TYPEID memoryViewType, + const char* name); + void _embind_register_function( const char* name, unsigned argCount, diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 185cc935..b712d164 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -10,7 +10,6 @@ namespace emscripten { extern "C" { void _emval_register_symbol(const char*); - typedef struct _EM_SIG* EM_SIG; typedef struct _EM_VAL* EM_VAL; void _emval_incref(EM_VAL value); diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h index e4ddfd04..32080e54 100644 --- a/system/include/emscripten/wire.h +++ b/system/include/emscripten/wire.h @@ -312,4 +312,77 @@ namespace emscripten { WireType wt; }; } + + struct memory_view { + enum class Type { + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + }; + + memory_view() = delete; + explicit memory_view(size_t size, const void* data) + : type(Type::Uint8Array) + , size(size) + , data(data) + {} + explicit memory_view(Type type, size_t size, const void* data) + : type(type) + , size(size) + , data(data) + {} + + const Type type; + const size_t size; // in elements, not bytes + const void* const data; + }; + + inline memory_view typed_memory_view(size_t size, const int8_t* data) { + return memory_view(memory_view::Type::Int8Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const uint8_t* data) { + return memory_view(memory_view::Type::Uint8Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const int16_t* data) { + return memory_view(memory_view::Type::Int16Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const uint16_t* data) { + return memory_view(memory_view::Type::Uint16Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const int32_t* data) { + return memory_view(memory_view::Type::Int32Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const uint32_t* data) { + return memory_view(memory_view::Type::Uint32Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const float* data) { + return memory_view(memory_view::Type::Float32Array, size, data); + } + + inline memory_view typed_memory_view(size_t size, const double* data) { + return memory_view(memory_view::Type::Float64Array, size, data); + } + + namespace internal { + template<> + struct BindingType<memory_view> { + typedef memory_view* WireType; + static WireType toWireType(const memory_view& mv) { + WireType wt = (WireType)malloc(sizeof(memory_view)); + new(wt) memory_view(mv); + return wt; + } + }; + } } diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index ec1648a9..12264dfd 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -59,4 +59,5 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { _embind_register_std_string(TypeID<std::string>::get(), "std::string");
_embind_register_std_wstring(TypeID<std::wstring>::get(), sizeof(wchar_t), "std::wstring");
_embind_register_emval(TypeID<val>::get(), "emscripten::val");
+ _embind_register_memory_view(TypeID<memory_view>::get(), "emscripten::memory_view");
}
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 52b2cad8..f9f035f2 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1728,6 +1728,28 @@ module({ e.delete(); f.delete(); }); + + BaseFixture.extend("memory view", function() { + test("can pass memory view from C++ to JS", function() { + var views = []; + cm.callWithMemoryView(function(view) { + views.push(view); + }); + assert.equal(3, views.length); + + assert.instanceof(views[0], Uint8Array); + assert.equal(8, views[0].length); + assert.deepEqual([0, 1, 2, 3, 4, 5, 6, 7], [].slice.call(new Uint8Array(views[0]))); + + assert.instanceof(views[1], Float32Array); + assert.equal(4, views[1].length); + assert.deepEqual([1.5, 2.5, 3.5, 4.5], [].slice.call(views[1])); + + assert.instanceof(views[2], Int16Array); + assert.equal(4, views[2].length); + assert.deepEqual([1000, 100, 10, 1], [].slice.call(views[2])); + }); + }); }); /* global run_all_tests */ diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 23761efc..e8ca0338 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1148,6 +1148,25 @@ EMSCRIPTEN_BINDINGS(interface_tests) { function("callDifferentArguments", &callDifferentArguments); } +template<typename T, size_t sizeOfArray> +constexpr size_t getElementCount(T (&)[sizeOfArray]) { + return sizeOfArray; +} + +static void callWithMemoryView(val v) { + // static so the JS test can read the memory after callTakeMemoryView runs + static unsigned char data[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + v(memory_view(getElementCount(data), data)); + static float f[] = { 1.5f, 2.5f, 3.5f, 4.5f }; + v(typed_memory_view(getElementCount(f), f)); + static short s[] = { 1000, 100, 10, 1 }; + v(typed_memory_view(getElementCount(s), s)); +} + +EMSCRIPTEN_BINDINGS(memory_view_tests) { + function("callWithMemoryView", &callWithMemoryView); +} + class HasExternalConstructor { public: HasExternalConstructor(const std::string& str) |