diff options
Diffstat (limited to 'src/webGLClient.js')
-rw-r--r-- | src/webGLClient.js | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/webGLClient.js b/src/webGLClient.js new file mode 100644 index 00000000..397cfa8c --- /dev/null +++ b/src/webGLClient.js @@ -0,0 +1,234 @@ +// WebGLWorker client code + +function assert(x) { + if (!x) throw 'failed assert'; +} + +function WebGLClient() { + var objects = {}; + + var ctx = null; + var buffer = null; + var i = 0; + + function func0(name) { + ctx[name](); + } + function func1(name) { + ctx[name](buffer[i]); + i++; + } + function func2(name) { + ctx[name](buffer[i], buffer[i+1]); + i += 2; + } + function func3(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2]); + i += 3; + } + function func4(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]); + i += 4; + } + function func5(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4]); + i += 5; + } + function func6(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5]); + i += 6; + } + function func7(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5], buffer[i+6]); + i += 7; + } + function func9(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]); + i += 9; + } + + // lookuppers, convert integer ids to cached objects for some args + function func1L0(name) { + ctx[name](objects[buffer[i]]); + i++; + } + function func2L0(name) { + ctx[name](objects[buffer[i]], buffer[i+1]); + i += 2; + } + function func2L0L1(name) { + ctx[name](objects[buffer[i]], objects[buffer[i+1]]); + i += 2; + } + function func2L1_(name) { + ctx[name](buffer[i], buffer[i+1] ? objects[buffer[i+1]] : null); + i += 2; + } + function func3L0(name) { + ctx[name](objects[buffer[i]], buffer[i+1], buffer[i+2]); + i += 3; + } + function func4L3_(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3] ? objects[buffer[i+3]] : null); + i += 4; + } + function func5L3_(name) { + ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3] ? objects[buffer[i+3]] : null, buffer[i+4]); + i += 5; + } + + // constructors, last argument is the id to save as + function funcC0(name) { + var object = ctx[name](); + var id = buffer[i++]; + objects[id] = object; + } + function funcC1(name) { + var object = ctx[name](buffer[i++]); + var id = buffer[i++]; + objects[id] = object; + } + function funcC2(name) { + var object = ctx[name](buffer[i++], buffer[i++]); + var id = buffer[i++]; + objects[id] = object; + } + function funcC2L0(name) { + var object = ctx[name](objects[buffer[i++]], buffer[i++]); + var id = buffer[i++]; + objects[id] = object; + } + + // destructors, stop holding on to the object in the cache + function funcD0(name) { + var id = buffer[i++]; + var object = objects[id]; + objects[id] = null; + ctx[name](object); + } + + var calls = { + 0: { name: 'NULL', func: func0 }, + 1: { name: 'getExtension', func: func1 }, + 2: { name: 'enable', func: func1 }, + 3: { name: 'disable', func: func1 }, + 4: { name: 'clear', func: func1 }, + 5: { name: 'clearColor', func: func4 }, + 6: { name: 'createShader', func: funcC1 }, + 7: { name: 'deleteShader', func: funcD0 }, + 8: { name: 'shaderSource', func: func2L0 }, + 9: { name: 'compileShader', func: func1L0 }, + 10: { name: 'createProgram', func: funcC0 }, + 11: { name: 'deleteProgram', func: funcD0 }, + 12: { name: 'attachShader', func: func2L0L1 }, + 13: { name: 'bindAttribLocation', func: func3L0 }, + 14: { name: 'linkProgram', func: func1L0 }, + 15: { name: 'getProgramParameter', func: function() { assert(ctx.getProgramParameter(objects[buffer[i++]], buffer[i++]), 'we cannot handle errors, we are async proxied WebGL'); } }, + 16: { name: 'getUniformLocation', func: funcC2L0 }, + 17: { name: 'useProgram', func: func1L0 }, + 18: { name: 'uniform1i', func: func2L0 }, + 19: { name: 'uniform1f', func: func2L0 }, + 20: { name: 'uniform3fv', func: func2L0 }, + 21: { name: 'uniform4fv', func: func2L0 }, + 22: { name: 'uniformMatrix4fv', func: func3L0 }, + 23: { name: 'vertexAttrib4fv', func: func2 }, + 24: { name: 'createBuffer', func: funcC0 }, + 25: { name: 'deleteBuffer', func: funcD0 }, + 26: { name: 'bindBuffer', func: func2L1_ }, + 27: { name: 'bufferData', func: func3 }, + 28: { name: 'bufferSubData', func: func3 }, + 29: { name: 'viewport', func: func4 }, + 30: { name: 'vertexAttribPointer', func: func6 }, + 31: { name: 'enableVertexAttribArray', func: func1 }, + 32: { name: 'disableVertexAttribArray', func: func1 }, + 33: { name: 'drawArrays', func: func3 }, + 34: { name: 'drawElements', func: func4 }, + 35: { name: 'getError', func: function() { assert(ctx.getError() === ctx.NO_ERROR, 'we cannot handle errors, we are async proxied WebGL') } }, + 36: { name: 'createTexture', func: funcC0 }, + 37: { name: 'deleteTexture', func: funcD0 }, + 38: { name: 'bindTexture', func: func2L1_ }, + 39: { name: 'texParameteri', func: func3 }, + 40: { name: 'texImage2D', func: func9 }, + 41: { name: 'compressedTexImage2D', func: func7 }, + 42: { name: 'activeTexture', func: func1 }, + 43: { name: 'getShaderParameter', func: function() { assert(ctx.getShaderParameter(objects[buffer[i++]], buffer[i++]), 'we cannot handle errors, we are async proxied WebGL'); } }, + 44: { name: 'clearDepth', func: func1 }, + 45: { name: 'depthFunc', func: func1 }, + 46: { name: 'frontFace', func: func1 }, + 47: { name: 'cullFace', func: func1 }, + 48: { name: 'pixelStorei', func: func2 }, + 49: { name: 'depthMask', func: func1 }, + 50: { name: 'depthRange', func: func2 }, + 51: { name: 'blendFunc', func: func2 }, + 52: { name: 'scissor', func: func4 }, + 53: { name: 'colorMask', func: func4 }, + 54: { name: 'lineWidth', func: func1 }, + 55: { name: 'createFramebuffer', func: funcC0 }, + 56: { name: 'deleteFramebuffer', func: funcD0 }, + 57: { name: 'bindFramebuffer', func: func2L1_ }, + 58: { name: 'framebufferTexture2D', func: func5L3_ }, + 59: { name: 'createRenderbuffer', func: funcC0 }, + 60: { name: 'deleteRenderbuffer', func: funcD0 }, + 61: { name: 'bindRenderbuffer', func: func2L1_ }, + 62: { name: 'renderbufferStorage', func: func4 }, + 63: { name: 'framebufferRenderbuffer', func: func4L3_ }, + 64: { name: 'debugPrint', func: func1 }, + }; + + function renderCommands(buf) { + ctx = Module.ctx; + i = 0; + buffer = buf; + var len = buffer.length; + //dump('issuing commands, buffer len: ' + len + '\n'); + while (i < len) { + var info = calls[buffer[i++]]; + var name = info.name; + info.func(name); + //var err; + //while ((err = ctx.getError()) !== ctx.NO_ERROR) { + // dump('warning: GL error ' + err + ', after ' + [command, numArgs] + '\n'); + //} + assert(i <= len); + } + } + + var commandBuffers = []; + + function renderAllCommands() { + // TODO: we can avoid running commands from buffers that are not the last, if they + // have no side effects, as each buffer is from a different frame + //if (commandBuffers.length > 1) dump('extra buffs: ' + (commandBuffers.length-1) + '\n'); + for (var i = 0; i < commandBuffers.length; i++) { + renderCommands(commandBuffers[i]); + } + commandBuffers.length = 0; + } + + this.onmessage = function(msg) { + //dump('client GL got ' + JSON.stringify(msg) + '\n'); + switch(msg.op) { + case 'render': { + if (commandBuffers.length === 0) { + // requestion a new frame, we will clear the buffers after rendering them + window.requestAnimationFrame(renderAllCommands); + } + commandBuffers.push(msg.commandBuffer); + break; + } + default: throw 'weird gl onmessage ' + JSON.stringify(msg); + } + }; +} + +WebGLClient.prefetch = function() { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('webgl-experimental') || canvas.getContext('webgl'); + if (!ctx) return; + var parameters = {}; + ['MAX_VERTEX_ATTRIBS', 'MAX_TEXTURE_IMAGE_UNITS', 'MAX_TEXTURE_SIZE', 'MAX_CUBE_MAP_TEXTURE_SIZE', 'MAX_VERTEX_UNIFORM_VECTORS', 'MAX_FRAGMENT_UNIFORM_VECTORS', 'MAX_VARYING_VECTORS', 'MAX_COMBINED_TEXTURE_IMAGE_UNITS', 'VENDOR', 'RENDERER', 'VERSION'].forEach(function(name) { + parameters[ctx[name]] = ctx.getParameter(ctx[name]); + }); + worker.postMessage({ target: 'gl', op: 'setPrefetched', parameters: parameters, extensions: ctx.getSupportedExtensions() }); +}; + |