Thomas Bergwinkl
Node Packaged Modules, kurz npm, stellt ca. 29000 Module zur Verfügung
Im ECMA-262 Standard sind folgende Datentypen definiert:
Null, Boolean, String, Number, Object
Number ist als Float definiert:
The Number type has exactly 18437736874454810627 (that is, 2^64-2^53+3) values, representing the double-precision 64-bit format IEEE 754 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic...
Reservierter Speicher
[ Constructor(unsigned long length) ]
interface ArrayBuffer {
readonly attribute unsigned long byteLength;
ArrayBuffer slice(long begin, optional long end);
};
Zeiger auf einen Bereich des ArrayBuffer mit typisiertem Zugriff
interface ArrayBufferView {
readonly attribute ArrayBuffer buffer;
readonly attribute unsigned long byteOffset;
readonly attribute unsigned long byteLength;
};
Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array
[
Constructor(unsigned long length),
Constructor(TypedArray array),
Constructor(type[] array),
Constructor(ArrayBuffer buffer, optional unsigned long byteOffset,
optional unsigned long length)
]
interface TypedArray {
const unsigned long BYTES_PER_ELEMENT = element size in bytes;
readonly attribute unsigned long length;
getter type get(unsigned long index);
setter void set(unsigned long index, type value);
void set(TypedArray array, optional unsigned long offset);
void set(type[] array, optional unsigned long offset);
TypedArray subarray(long begin, optional long end);
};
TypedArray implements ArrayBufferView;
// 8-byte ArrayBuffer erstellen
var b = new ArrayBuffer(8);
// View mit Referenz auf b vom Typ Int32 erstellen
// über die gesammte Länge des ArrayBuffer
// beginnend bei Byte-Index 0 (Default Wert)
var v1 = new Int32Array(b);
// View mit Referenz auf b vom Typ Uint8 erstellen
// über die gesammte Länge des ArrayBuffer
// beginnend bei Byte Index 2
var v2 = new Uint8Array(b, 2);
// View mit Referenz auf b vom Typ Int16 erstellen
// mit der Länge 2 (Array Elemente)
// beginnend bei Byte Index 2
var v3 = new Int16Array(b, 2, 2);
var | index | |||||||
---|---|---|---|---|---|---|---|---|
b = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
v1 = | 0 | 1 | ||||||
v2 = | 0 | 1 | 2 | 3 | 4 | 5 | ||
v3 = | 0 | 1 |
interface Worker {
attribute EventHandler onmessage;
void terminate();
void postMessage(any message, optional sequence<Transferable> transfer);
};
interface MessagePort : EventTarget {
void postMessage(any message, optional sequence<Transferable> transfer);
void start();
void close();
attribute EventHandler onmessage;
};
interface WorkerGlobalScope {
readonly attribute WorkerGlobalScope self;
attribute EventHandler onmessage;
attribute EventHandler onerror;
attribute EventHandler onoffline;
attribute EventHandler ononline;
void close();
void importScripts(DOMString... urls);
void postMessage(any message, optional sequence<Transferable> transfer);
};
interface MessageEvent : Event {
readonly attribute any data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
readonly attribute (WindowProxy or MessagePort)? source;
readonly attribute MessagePort[]? ports;
};
<html>
<body>
<script>
console.time("worker");
var worker = new Worker("worker.js");
worker.addEventListener("message", function(event) {
console.log("worker response: ", event.data);
console.timeEnd("worker");
}, false);
worker.postMessage(1);
</script>
</body>
</html>
self.addEventListener("message", function(event) {
self.postMessage(event.data+event.data);
}, false);
var workerSource = ["self.addEventListener("message", function(event) { self.postMessage(event.data+event.data); }, false);"];
var workerBlob = new Blob(workerSource, { "type" : "application\/javascript" });
var workerUrl = URL.createObjectURL(workerBlob);
ImportScripts-Funktion erlaubt es weitere Scripts nachzuladen
importScripts('script1.js', 'script2.js');
OpenCL API für JavaScript
Host verbunden mit einem oder mehreren OpenCL Geräten
interface WebCL {
sequence<WebCLPlatform> getPlatforms();
WebCLContext? createContext(optional WebCLContextProperties properties);
void waitForEvents(WebCLEvent[] eventWaitList, optional WebCLCallback whenFinished, optional any userdata);
};
interface WebCLPlatform {
sequence<WebCLDevice> getDevices(CLenum deviceType);
};
Verbindet Geräte, Programme, Kernels, Buffers und Command Queues
Zur Übertragung von Daten, lesend und schreibend, an einen Context
interface WebCLContext {
WebCLBuffer createBuffer(CLenum memFlags, CLuint sizeInBytes, optional ArrayBuffer hostPtr);
WebCLCommandQueue createCommandQueue(optional WebCLDevice? device, optional CLenum properties);
WebCLProgram createProgram(DOMString source);
};
Mit __kernel markierte Funktion als Programmeinstiegspunkt
interface WebCLProgram {
any getBuildInfo(WebCLDevice device, CLenum name);
void build(WebCLDevice[] devices, optional DOMString? options, optional WebCLCallback whenFinished, optional any userdata);
WebCLKernel createKernel(DOMString kernelName);
};
interface WebCLKernel {
void setArg(CLuint index, any value, optional CLtype type);
};
Zur Verwaltung von Rechenoperationen
interface WebCLCommandQueue {
void enqueueReadBuffer(WebCLBuffer buffer, CLboolean blockingRead, CLuint bufferOffset, CLuint numBytes, ArrayBuffer hostPtr, optional WebCLEvent[]? eventWaitList, optional WebCLEvent? event);
void enqueueWriteBuffer(WebCLBuffer buffer, CLboolean blockingWrite, CLuint bufferOffset, CLuint numBytes, ArrayBuffer hostPtr, optional WebCLEvent[]? eventWaitList, optional WebCLEvent? event);
void enqueueNDRangeKernel(
WebCLKernel kernel,
CLuint[3]? globalWorkOffset, CLuint[3]? globalWorkSize, CLuint[3]? localWorkSize,
optional WebCLEvent[]? eventWaitList,
optional WebCLEvent? event);
void finish();
};
var cl = require("node-webcl");
var platforms = cl.getPlatforms();
var context = cl.createContext({deviceType:cl.DEVICE_TYPE_DEFAULT, platform: platforms[0]});
var devices = context.getInfo(cl.CONTEXT_DEVICES);
var source =
"__kernel void add(__global const ushort* input, __global ushort* output, uint value) {" +
" int index = get_global_id(0);" +
" if (index < 0 || index > 3) return;" +
" output[index] = input[index] + value; }";
var program = context.createProgram(source);
program.build([devices[0]]);
var inArray = new Uint16Array([1,2,3,4]);
var outArray = new Uint16Array(4);
var inBuffer = context.createBuffer(cl.MEM_READ_ONLY, inArray.byteLength);
var outBuffer = context.createBuffer(cl.MEM_WRITE_ONLY, outArray.byteLength);
var kernel = program.createKernel("add");
kernel.setArg(0, inBuffer);
kernel.setArg(1, outBuffer);
kernel.setArg(2, 10, cl.type.UINT);
var commandQueue = context.createCommandQueue(devices[0]);
commandQueue.enqueueWriteBuffer(inBuffer, false, 0, inArray.byteLength, inArray.buffer);
commandQueue.enqueueNDRangeKernel(kernel, null, [4], [2]);
commandQueue.enqueueReadBuffer(outBuffer, false, 0, outArray.byteLength, outArray.buffer);
commandQueue.finish();
console.log(outArray);
OpenGL API für JavaScript
interface WebGLRenderingContext {
void activeTexture(GLenum texture);
void attachShader(WebGLProgram? program, WebGLShader? shader);
void bindAttribLocation(WebGLProgram? program, GLuint index, DOMString name);
void bindBuffer(GLenum target, WebGLBuffer? buffer);
void bindTexture(GLenum target, WebGLTexture? texture);
void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
void clear(GLbitfield mask);
void compileShader(WebGLShader? shader);
WebGLBuffer? createBuffer();
WebGLProgram? createProgram();
WebGLShader? createShader(GLenum type);
WebGLTexture? createTexture();
void drawArrays(GLenum mode, GLint first, GLsizei count);
[WebGLHandlesContextLoss] GLint getAttribLocation(WebGLProgram? program, DOMString name);
void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
void uniform1f(WebGLUniformLocation? location, GLfloat x);
void uniform1fv(WebGLUniformLocation? location, Float32Array v);
void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w);
void uniform4iv(WebGLUniformLocation? location, Int32Array v);
void uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value);
void useProgram(WebGLProgram? program);
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
};
<html>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = window.document.getElementById("canvas");
var gl = canvas.getContext("experimental-webgl");
var program = gl.createProgram();
var vertexShaderSource =
"attribute vec4 position;" +
"void main() { gl_Position = position; }";
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);
var fragmentShaderSource =
"void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }";
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var positionsAttribute = gl.getAttribLocation(program, "position");
var positions = new Float32Array([0.0, 0.1, 0.0, -0.1, -0.1, 0.0, 0.1, -0.1, 0.0]);
var positionsBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl.vertexAttribPointer(positionsAttribute, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionsAttribute);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
RequireJS wurde als Module Loader gewählt weil:
Light Version von RequireJS speziell für Web Worker
Uint16Array wird in zwei Uint8Arrays (low/high) verteilt und im Shader-Code wieder zusammengefügt
3D Textur wird "aufgeklappt" und in 2D abgebildet
Startet für jeden Worker einen neuen Node Prozess und kommuniziert über Unix Sockets mit Web Socket API
Web Worker Modul implementiert als C++ Node.js Erweiterung