diff options
Diffstat (limited to 'src/webGLWorker.js')
-rw-r--r-- | src/webGLWorker.js | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/src/webGLWorker.js b/src/webGLWorker.js new file mode 100644 index 00000000..90a1bed9 --- /dev/null +++ b/src/webGLWorker.js @@ -0,0 +1,910 @@ +// WebGLWorker worker code + +function WebGLBuffer(id) { + this.what = 'buffer'; + this.id = id; +} +function WebGLProgram(id) { + this.what = 'program'; + this.id = id; + this.shaders = []; + this.attributes = {}; + this.attributeVec = []; +} +function WebGLFramebuffer(id) { + this.what = 'frameBuffer'; + this.id = id; +} +function WebGLRenderbuffer(id) { + this.what = 'renderBuffer'; + this.id = id; +} +function WebGLTexture(id) { + this.what = 'texture'; + this.id = id; + this.binding = 0; +} + +function WebGLWorker() { + //======= + // State + //======= + + var commandBuffer = []; + + var nextId = 1; // valid ids are > 0 + + var bindings = { + texture2D: null, + arrayBuffer: null, + elementArrayBuffer: null, + program: null + }; + + //=========== + // Constants + //=========== + + /* ClearBufferMask */ + this.DEPTH_BUFFER_BIT = 0x00000100; + this.STENCIL_BUFFER_BIT = 0x00000400; + this.COLOR_BUFFER_BIT = 0x00004000; + + /* BeginMode */ + this.POINTS = 0x0000; + this.LINES = 0x0001; + this.LINE_LOOP = 0x0002; + this.LINE_STRIP = 0x0003; + this.TRIANGLES = 0x0004; + this.TRIANGLE_STRIP = 0x0005; + this.TRIANGLE_FAN = 0x0006; + + /* AlphaFunction (not supported in ES20) */ + /* NEVER */ + /* LESS */ + /* EQUAL */ + /* LEQUAL */ + /* GREATER */ + /* NOTEQUAL */ + /* GEQUAL */ + /* ALWAYS */ + + /* BlendingFactorDest */ + this.ZERO = 0; + this.ONE = 1; + this.SRC_COLOR = 0x0300; + this.ONE_MINUS_SRC_COLOR = 0x0301; + this.SRC_ALPHA = 0x0302; + this.ONE_MINUS_SRC_ALPHA = 0x0303; + this.DST_ALPHA = 0x0304; + this.ONE_MINUS_DST_ALPHA = 0x0305; + + /* BlendingFactorSrc */ + /* ZERO */ + /* ONE */ + this.DST_COLOR = 0x0306; + this.ONE_MINUS_DST_COLOR = 0x0307; + this.SRC_ALPHA_SATURATE = 0x0308; + /* SRC_ALPHA */ + /* ONE_MINUS_SRC_ALPHA */ + /* DST_ALPHA */ + /* ONE_MINUS_DST_ALPHA */ + + /* BlendEquationSeparate */ + this.FUNC_ADD = 0x8006; + this.BLEND_EQUATION = 0x8009; + this.BLEND_EQUATION_RGB = 0x8009; /* same as BLEND_EQUATION */ + this.BLEND_EQUATION_ALPHA = 0x883D; + + /* BlendSubtract */ + this.FUNC_SUBTRACT = 0x800A; + this.FUNC_REVERSE_SUBTRACT = 0x800B; + + /* Separate Blend Functions */ + this.BLEND_DST_RGB = 0x80C8; + this.BLEND_SRC_RGB = 0x80C9; + this.BLEND_DST_ALPHA = 0x80CA; + this.BLEND_SRC_ALPHA = 0x80CB; + this.CONSTANT_COLOR = 0x8001; + this.ONE_MINUS_CONSTANT_COLOR = 0x8002; + this.CONSTANT_ALPHA = 0x8003; + this.ONE_MINUS_CONSTANT_ALPHA = 0x8004; + this.BLEND_COLOR = 0x8005; + + /* Buffer Objects */ + this.ARRAY_BUFFER = 0x8892; + this.ELEMENT_ARRAY_BUFFER = 0x8893; + this.ARRAY_BUFFER_BINDING = 0x8894; + this.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + + this.STREAM_DRAW = 0x88E0; + this.STATIC_DRAW = 0x88E4; + this.DYNAMIC_DRAW = 0x88E8; + + this.BUFFER_SIZE = 0x8764; + this.BUFFER_USAGE = 0x8765; + + this.CURRENT_VERTEX_ATTRIB = 0x8626; + + /* CullFaceMode */ + this.FRONT = 0x0404; + this.BACK = 0x0405; + this.FRONT_AND_BACK = 0x0408; + + /* DepthFunction */ + /* NEVER */ + /* LESS */ + /* EQUAL */ + /* LEQUAL */ + /* GREATER */ + /* NOTEQUAL */ + /* GEQUAL */ + /* ALWAYS */ + + /* EnableCap */ + /* TEXTURE_2D */ + this.CULL_FACE = 0x0B44; + this.BLEND = 0x0BE2; + this.DITHER = 0x0BD0; + this.STENCIL_TEST = 0x0B90; + this.DEPTH_TEST = 0x0B71; + this.SCISSOR_TEST = 0x0C11; + this.POLYGON_OFFSET_FILL = 0x8037; + this.SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + this.SAMPLE_COVERAGE = 0x80A0; + + /* ErrorCode */ + this.NO_ERROR = 0; + this.INVALID_ENUM = 0x0500; + this.INVALID_VALUE = 0x0501; + this.INVALID_OPERATION = 0x0502; + this.OUT_OF_MEMORY = 0x0505; + + /* FrontFaceDirection */ + this.CW = 0x0900; + this.CCW = 0x0901; + + /* GetPName */ + this.LINE_WIDTH = 0x0B21; + this.ALIASED_POINT_SIZE_RANGE = 0x846D; + this.ALIASED_LINE_WIDTH_RANGE = 0x846E; + this.CULL_FACE_MODE = 0x0B45; + this.FRONT_FACE = 0x0B46; + this.DEPTH_RANGE = 0x0B70; + this.DEPTH_WRITEMASK = 0x0B72; + this.DEPTH_CLEAR_VALUE = 0x0B73; + this.DEPTH_FUNC = 0x0B74; + this.STENCIL_CLEAR_VALUE = 0x0B91; + this.STENCIL_FUNC = 0x0B92; + this.STENCIL_FAIL = 0x0B94; + this.STENCIL_PASS_DEPTH_FAIL = 0x0B95; + this.STENCIL_PASS_DEPTH_PASS = 0x0B96; + this.STENCIL_REF = 0x0B97; + this.STENCIL_VALUE_MASK = 0x0B93; + this.STENCIL_WRITEMASK = 0x0B98; + this.STENCIL_BACK_FUNC = 0x8800; + this.STENCIL_BACK_FAIL = 0x8801; + this.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; + this.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; + this.STENCIL_BACK_REF = 0x8CA3; + this.STENCIL_BACK_VALUE_MASK = 0x8CA4; + this.STENCIL_BACK_WRITEMASK = 0x8CA5; + this.VIEWPORT = 0x0BA2; + this.SCISSOR_BOX = 0x0C10; + /* SCISSOR_TEST */ + this.COLOR_CLEAR_VALUE = 0x0C22; + this.COLOR_WRITEMASK = 0x0C23; + this.UNPACK_ALIGNMENT = 0x0CF5; + this.PACK_ALIGNMENT = 0x0D05; + this.MAX_TEXTURE_SIZE = 0x0D33; + this.MAX_VIEWPORT_DIMS = 0x0D3A; + this.SUBPIXEL_BITS = 0x0D50; + this.RED_BITS = 0x0D52; + this.GREEN_BITS = 0x0D53; + this.BLUE_BITS = 0x0D54; + this.ALPHA_BITS = 0x0D55; + this.DEPTH_BITS = 0x0D56; + this.STENCIL_BITS = 0x0D57; + this.POLYGON_OFFSET_UNITS = 0x2A00; + /* POLYGON_OFFSET_FILL */ + this.POLYGON_OFFSET_FACTOR = 0x8038; + this.TEXTURE_BINDING_2D = 0x8069; + this.SAMPLE_BUFFERS = 0x80A8; + this.SAMPLES = 0x80A9; + this.SAMPLE_COVERAGE_VALUE = 0x80AA; + this.SAMPLE_COVERAGE_INVERT = 0x80AB; + + /* GetTextureParameter */ + /* TEXTURE_MAG_FILTER */ + /* TEXTURE_MIN_FILTER */ + /* TEXTURE_WRAP_S */ + /* TEXTURE_WRAP_T */ + + this.COMPRESSED_TEXTURE_FORMATS = 0x86A3; + + /* HintMode */ + this.DONT_CARE = 0x1100; + this.FASTEST = 0x1101; + this.NICEST = 0x1102; + + /* HintTarget */ + this.GENERATE_MIPMAP_HINT = 0x8192; + + /* DataType */ + this.BYTE = 0x1400; + this.UNSIGNED_BYTE = 0x1401; + this.SHORT = 0x1402; + this.UNSIGNED_SHORT = 0x1403; + this.INT = 0x1404; + this.UNSIGNED_INT = 0x1405; + this.FLOAT = 0x1406; + + /* PixelFormat */ + this.DEPTH_COMPONENT = 0x1902; + this.ALPHA = 0x1906; + this.RGB = 0x1907; + this.RGBA = 0x1908; + this.LUMINANCE = 0x1909; + this.LUMINANCE_ALPHA = 0x190A; + + /* PixelType */ + /* UNSIGNED_BYTE */ + this.UNSIGNED_SHORT_4_4_4_4 = 0x8033; + this.UNSIGNED_SHORT_5_5_5_1 = 0x8034; + this.UNSIGNED_SHORT_5_6_5 = 0x8363; + + /* Shaders */ + this.FRAGMENT_SHADER = 0x8B30; + this.VERTEX_SHADER = 0x8B31; + this.MAX_VERTEX_ATTRIBS = 0x8869; + this.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; + this.MAX_VARYING_VECTORS = 0x8DFC; + this.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; + this.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; + this.MAX_TEXTURE_IMAGE_UNITS = 0x8872; + this.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; + this.SHADER_TYPE = 0x8B4F; + this.DELETE_STATUS = 0x8B80; + this.LINK_STATUS = 0x8B82; + this.VALIDATE_STATUS = 0x8B83; + this.ATTACHED_SHADERS = 0x8B85; + this.ACTIVE_UNIFORMS = 0x8B86; + this.ACTIVE_ATTRIBUTES = 0x8B89; + this.SHADING_LANGUAGE_VERSION = 0x8B8C; + this.CURRENT_PROGRAM = 0x8B8D; + + /* StencilFunction */ + this.NEVER = 0x0200; + this.LESS = 0x0201; + this.EQUAL = 0x0202; + this.LEQUAL = 0x0203; + this.GREATER = 0x0204; + this.NOTEQUAL = 0x0205; + this.GEQUAL = 0x0206; + this.ALWAYS = 0x0207; + + /* StencilOp */ + /* ZERO */ + this.KEEP = 0x1E00; + this.REPLACE = 0x1E01; + this.INCR = 0x1E02; + this.DECR = 0x1E03; + this.INVERT = 0x150A; + this.INCR_WRAP = 0x8507; + this.DECR_WRAP = 0x8508; + + /* StringName */ + this.VENDOR = 0x1F00; + this.RENDERER = 0x1F01; + this.VERSION = 0x1F02; + + /* TextureMagFilter */ + this.NEAREST = 0x2600; + this.LINEAR = 0x2601; + + /* TextureMinFilter */ + /* NEAREST */ + /* LINEAR */ + this.NEAREST_MIPMAP_NEAREST = 0x2700; + this.LINEAR_MIPMAP_NEAREST = 0x2701; + this.NEAREST_MIPMAP_LINEAR = 0x2702; + this.LINEAR_MIPMAP_LINEAR = 0x2703; + + /* TextureParameterName */ + this.TEXTURE_MAG_FILTER = 0x2800; + this.TEXTURE_MIN_FILTER = 0x2801; + this.TEXTURE_WRAP_S = 0x2802; + this.TEXTURE_WRAP_T = 0x2803; + + /* TextureTarget */ + this.TEXTURE_2D = 0x0DE1; + this.TEXTURE = 0x1702; + + this.TEXTURE_CUBE_MAP = 0x8513; + this.TEXTURE_BINDING_CUBE_MAP = 0x8514; + this.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; + this.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; + this.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; + this.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; + this.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; + this.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; + this.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; + + /* TextureUnit */ + this.TEXTURE0 = 0x84C0; + this.TEXTURE1 = 0x84C1; + this.TEXTURE2 = 0x84C2; + this.TEXTURE3 = 0x84C3; + this.TEXTURE4 = 0x84C4; + this.TEXTURE5 = 0x84C5; + this.TEXTURE6 = 0x84C6; + this.TEXTURE7 = 0x84C7; + this.TEXTURE8 = 0x84C8; + this.TEXTURE9 = 0x84C9; + this.TEXTURE10 = 0x84CA; + this.TEXTURE11 = 0x84CB; + this.TEXTURE12 = 0x84CC; + this.TEXTURE13 = 0x84CD; + this.TEXTURE14 = 0x84CE; + this.TEXTURE15 = 0x84CF; + this.TEXTURE16 = 0x84D0; + this.TEXTURE17 = 0x84D1; + this.TEXTURE18 = 0x84D2; + this.TEXTURE19 = 0x84D3; + this.TEXTURE20 = 0x84D4; + this.TEXTURE21 = 0x84D5; + this.TEXTURE22 = 0x84D6; + this.TEXTURE23 = 0x84D7; + this.TEXTURE24 = 0x84D8; + this.TEXTURE25 = 0x84D9; + this.TEXTURE26 = 0x84DA; + this.TEXTURE27 = 0x84DB; + this.TEXTURE28 = 0x84DC; + this.TEXTURE29 = 0x84DD; + this.TEXTURE30 = 0x84DE; + this.TEXTURE31 = 0x84DF; + this.ACTIVE_TEXTURE = 0x84E0; + + /* TextureWrapMode */ + this.REPEAT = 0x2901; + this.CLAMP_TO_EDGE = 0x812F; + this.MIRRORED_REPEAT = 0x8370; + + /* Uniform Types */ + this.FLOAT_VEC2 = 0x8B50; + this.FLOAT_VEC3 = 0x8B51; + this.FLOAT_VEC4 = 0x8B52; + this.INT_VEC2 = 0x8B53; + this.INT_VEC3 = 0x8B54; + this.INT_VEC4 = 0x8B55; + this.BOOL = 0x8B56; + this.BOOL_VEC2 = 0x8B57; + this.BOOL_VEC3 = 0x8B58; + this.BOOL_VEC4 = 0x8B59; + this.FLOAT_MAT2 = 0x8B5A; + this.FLOAT_MAT3 = 0x8B5B; + this.FLOAT_MAT4 = 0x8B5C; + this.SAMPLER_2D = 0x8B5E; + this.SAMPLER_CUBE = 0x8B60; + + /* Vertex Arrays */ + this.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; + this.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; + this.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; + this.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; + this.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; + this.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; + this.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; + + /* Read Format */ + this.IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A; + this.IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B; + + /* Shader Source */ + this.COMPILE_STATUS = 0x8B81; + + /* Shader Precision-Specified Types */ + this.LOW_FLOAT = 0x8DF0; + this.MEDIUM_FLOAT = 0x8DF1; + this.HIGH_FLOAT = 0x8DF2; + this.LOW_INT = 0x8DF3; + this.MEDIUM_INT = 0x8DF4; + this.HIGH_INT = 0x8DF5; + + /* Framebuffer Object. */ + this.FRAMEBUFFER = 0x8D40; + this.RENDERBUFFER = 0x8D41; + + this.RGBA4 = 0x8056; + this.RGB5_A1 = 0x8057; + this.RGB565 = 0x8D62; + this.DEPTH_COMPONENT16 = 0x81A5; + this.STENCIL_INDEX = 0x1901; + this.STENCIL_INDEX8 = 0x8D48; + this.DEPTH_STENCIL = 0x84F9; + + this.RENDERBUFFER_WIDTH = 0x8D42; + this.RENDERBUFFER_HEIGHT = 0x8D43; + this.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; + this.RENDERBUFFER_RED_SIZE = 0x8D50; + this.RENDERBUFFER_GREEN_SIZE = 0x8D51; + this.RENDERBUFFER_BLUE_SIZE = 0x8D52; + this.RENDERBUFFER_ALPHA_SIZE = 0x8D53; + this.RENDERBUFFER_DEPTH_SIZE = 0x8D54; + this.RENDERBUFFER_STENCIL_SIZE = 0x8D55; + + this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; + this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; + this.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2; + this.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3; + + this.COLOR_ATTACHMENT0 = 0x8CE0; + this.DEPTH_ATTACHMENT = 0x8D00; + this.STENCIL_ATTACHMENT = 0x8D20; + this.DEPTH_STENCIL_ATTACHMENT = 0x821A; + + this.NONE = 0; + + this.FRAMEBUFFER_COMPLETE = 0x8CD5; + this.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6; + this.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7; + this.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9; + this.FRAMEBUFFER_UNSUPPORTED = 0x8CDD; + + this.FRAMEBUFFER_BINDING = 0x8CA6; + this.RENDERBUFFER_BINDING = 0x8CA7; + this.MAX_RENDERBUFFER_SIZE = 0x84E8; + + this.INVALID_FRAMEBUFFER_OPERATION = 0x0506; + + /* WebGL-specific enums */ + this.UNPACK_FLIP_Y_WEBGL = 0x9240; + this.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; + this.CONTEXT_LOST_WEBGL = 0x9242; + this.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243; + this.BROWSER_DEFAULT_WEBGL = 0x9244; + + //========== + // Functions + //========== + + var that = this; + + // Helpers + + this.onmessage = function(msg) { + //dump('worker GL got ' + JSON.stringify(msg) + '\n'); + switch(msg.op) { + case 'setPrefetched': { + WebGLWorker.prototype.prefetchedParameters = msg.parameters; + WebGLWorker.prototype.prefetchedExtensions = msg.extensions; + break; + } + default: throw 'weird gl onmessage ' + JSON.stringify(msg); + } + }; + + function revname(name) { + for (var x in that) if (that[x] === name) return x; + return null; + } + + // GL + + this.getParameter = function(name) { + assert(name); + if (name in this.prefetchedParameters) return this.prefetchedParameters[name]; + switch (name) { + case this.TEXTURE_BINDING_2D: { + return bindings.texture2D; + } + case this.ARRAY_BUFFER_BINDING: { + return bindings.arrayBuffer; + } + case this.ELEMENT_ARRAY_BUFFER_BINDING: { + return bindings.elementArrayBuffer; + } + case this.CURRENT_PROGRAM: { + return bindings.program; + } + default: throw 'TODO: get parameter ' + name + ' : ' + revname(name); + } + }; + this.getExtension = function(name) { + var i = this.prefetchedExtensions.indexOf(name); + if (i < 0) return null; + commandBuffer.push(1, name); + return true; // TODO: return an object here + }; + this.getSupportedExtensions = function() { + return this.prefetchedExtensions; + }; + this.enable = function(cap) { + commandBuffer.push(2, cap); + }; + this.disable = function(cap) { + commandBuffer.push(3, cap); + }; + this.clear = function(mask) { + commandBuffer.push(4, mask); + }; + this.clearColor = function(r, g, b, a) { + commandBuffer.push(5, r, g, b, a); + }; + this.createShader = function(type) { + var id = nextId++; + commandBuffer.push(6, type, id); + return { id: id, what: 'shader', type: type }; + }; + this.deleteShader = function(shader) { + if (!shader) return; + commandBuffer.push(7, shader.id); + }; + this.shaderSource = function(shader, source) { + shader.source = source; + commandBuffer.push(8, shader.id, source); + }; + this.compileShader = function(shader) { + commandBuffer.push(9, shader.id); + }; + this.getShaderInfoLog = function(shader) { + return ''; // optimistic assumption of success; no proxying + }; + this.createProgram = function() { + var id = nextId++; + commandBuffer.push(10, id); + return new WebGLProgram(id); + }; + this.deleteProgram = function(program) { + if (!program) return; + commandBuffer.push(11, program.id); + }; + this.attachShader = function(program, shader) { + program.shaders.push(shader); + commandBuffer.push(12, program.id, shader.id); + }; + this.bindAttribLocation = function(program, index, name) { + program.attributes[name] = { what: 'attribute', name: name, size: -1, location: index }; // fill in size later + program.attributeVec[index] = name; + commandBuffer.push(13, program.id, index, name); + }; + this.getAttribLocation = function(program, name) { + // all existing attribs are cached locally + if (name in program.attributes) return program.attributes[name].location; + return -1; + }; + this.linkProgram = function(program) { + // parse shader sources + function parseElementType(shader, type, obj, vec) { + var source = shader.source; + source = source.replace(/\n/g, '|\n'); // barrier between lines, to make regexing easier + var newItems = source.match(new RegExp(type + '\\s+\\w+\\s+[\\w,\\s\[\\]]+;', 'g')); + if (!newItems) return; + newItems.forEach(function(item) { + var m = new RegExp(type + '\\s+\\w+\\s+([\\w,\\s\[\\]]+);').exec(item); + assert(m); + m[1].split(',').map(function(name) { name = name.trim(); return name.search(/\s/) >= 0 ? '' : name }).filter(function(name) { return !!name }).forEach(function(name) { + var size = 1; + var open = name.indexOf('['); + var fullname = name; + if (open >= 0) { + var close = name.indexOf(']'); + size = parseInt(name.substring(open+1, close)); + name = name.substr(0, open); + fullname = name + '[0]'; + } + if (!obj[name]) { + obj[name] = { what: type, name: fullname, size: size, location: -1 }; + if (vec) vec.push(name); + } + }); + }); + } + + program.uniforms = {}; + program.uniformVec = []; + + var existingAttributes = {}; + + program.shaders.forEach(function(shader) { + parseElementType(shader, 'uniform', program.uniforms, program.uniformVec); + parseElementType(shader, 'attribute', existingAttributes, null); + }); + + // bind not-yet bound attributes + for (var attr in existingAttributes) { + if (!(attr in program.attributes)) { + var index = program.attributeVec.length; + this.bindAttribLocation(program, index, attr); + } + program.attributes[attr].size = existingAttributes[attr].size; + } + + commandBuffer.push(14, program.id); + }; + this.getProgramParameter = function(program, name) { + switch (name) { + case this.ACTIVE_UNIFORMS: return program.uniformVec.length; + case this.ACTIVE_ATTRIBUTES: return program.attributeVec.length; + case this.LINK_STATUS: { + // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow + commandBuffer.push(15, program.id, name); + return true; + } + default: throw 'bad getProgramParameter ' + revname(name); + } + }; + this.getActiveAttrib = function(program, index) { + var name = program.attributeVec[index]; + if (!name) return null; + return program.attributes[name]; + }; + this.getActiveUniform = function(program, index) { + var name = program.uniformVec[index]; + if (!name) return null; + return program.uniforms[name]; + }; + this.getUniformLocation = function(program, name) { + var fullname = name; + var index = -1; + var open = name.indexOf('['); + if (open >= 0) { + var close = name.indexOf(']'); + index = parseInt(name.substring(open+1, close)); + name = name.substr(0, open); + } + if (!(name in program.uniforms)) return null; + var id = nextId++; + commandBuffer.push(16, program.id, fullname, id); + return { what: 'location', uniform: program.uniforms[name], id: id, index: index }; + }; + this.getProgramInfoLog = function(shader) { + return ''; // optimistic assumption of success; no proxying + }; + this.useProgram = function(program) { + commandBuffer.push(17, program ? program.id : 0); + bindings.program = program; + }; + this.uniform1i = function(location, data) { + if (!location) return; + commandBuffer.push(18, location.id, data); + }; + this.uniform1f = function(location, data) { + if (!location) return; + commandBuffer.push(19, location.id, data); + }; + this.uniform3fv = function(location, data) { + if (!location) return; + commandBuffer.push(20, location.id, new Float32Array(data)); + }; + this.uniform4fv = function(location, data) { + if (!location) return; + commandBuffer.push(21, location.id, new Float32Array(data)); + }; + this.uniformMatrix4fv = function(location, transpose, data) { + if (!location) return; + commandBuffer.push(22, location.id, transpose, new Float32Array(data)); + }; + this.vertexAttrib4fv = function(index, values) { + commandBuffer.push(23, index, new Float32Array(values)); + }; + this.createBuffer = function() { + var id = nextId++; + commandBuffer.push(24, id); + return new WebGLBuffer(id); + }; + this.deleteBuffer = function(buffer) { + if (!buffer) return; + commandBuffer.push(25, buffer.id); + }; + this.bindBuffer = function(target, buffer) { + commandBuffer.push(26, target, buffer ? buffer.id : 0); + switch (target) { + case this.ARRAY_BUFFER_BINDING: { + bindings.arrayBuffer = buffer; + break; + } + case this.ELEMENT_ARRAY_BUFFER_BINDING: { + bindings.elementArrayBuffer = buffer; + break; + } + } + }; + this.bufferData = function(target, something, usage) { + if (typeof something !== 'number') something = new something.constructor(something); + commandBuffer.push(27, target, something, usage); + }; + this.bufferSubData = function(target, offset, something) { + if (typeof something !== 'number') something = new something.constructor(something); + commandBuffer.push(28, target, offset, something); + }; + this.viewport = function(x, y, w, h) { + commandBuffer.push(29, x, y, w, h); + }; + this.vertexAttribPointer = function(index, size, type, normalized, stride, offset) { + commandBuffer.push(30, index, size, type, normalized, stride, offset); + }; + this.enableVertexAttribArray = function(index) { + commandBuffer.push(31, index); + }; + this.disableVertexAttribArray = function(index) { + commandBuffer.push(32, index); + }; + this.drawArrays = function(mode, first, count) { + commandBuffer.push(33, mode, first, count); + }; + this.drawElements = function(mode, count, type, offset) { + commandBuffer.push(34, mode, count, type, offset); + }; + this.getError = function() { + // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow + commandBuffer.push(35); + return this.NO_ERROR; + }; + this.createTexture = function() { + var id = nextId++; + commandBuffer.push(36, id); + return new WebGLTexture(id); + }; + this.deleteTexture = function(texture) { + if (!texture) return; + commandBuffer.push(37, texture.id); + texture.id = 0; + }; + this.isTexture = function(texture) { + return texture && texture.what === 'texture' && texture.id > 0 && texture.binding; + }; + this.bindTexture = function(target, texture) { + switch (target) { + case that.TEXTURE_2D: { + bindings.texture2D = texture; + break; + } + } + texture.binding = target; + commandBuffer.push(38, target, texture ? texture.id : 0); + }; + this.texParameteri = function(target, pname, param) { + commandBuffer.push(39, target, pname, param); + }; + this.texImage2D = function(target, level, internalformat, width, height, border, format, type, pixels) { + assert(pixels || pixels === null); // we do not support the overloads that have fewer params + commandBuffer.push(40, target, level, internalformat, width, height, border, format, type, pixels ? new pixels.constructor(pixels) : pixels); + }; + this.compressedTexImage2D = function(target, level, internalformat, width, height, border, pixels) { + commandBuffer.push(41, target, level, internalformat, width, height, border, new pixels.constructor(pixels)); + }; + this.activeTexture = function(texture) { + commandBuffer.push(42, texture); + }; + this.getShaderParameter = function(shader, pname) { + switch (pname) { + case this.SHADER_TYPE: return shader.type; + case this.COMPILE_STATUS: { + // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow + commandBuffer.push(43, shader.id, pname); + return true; + } + default: throw 'unsupported getShaderParameter ' + pname; + } + }; + this.clearDepth = function(depth) { + commandBuffer.push(44, depth); + }; + this.depthFunc = function(depth) { + commandBuffer.push(45, depth); + }; + this.frontFace = function(depth) { + commandBuffer.push(46, depth); + }; + this.cullFace = function(depth) { + commandBuffer.push(47, depth); + }; + this.readPixels = function(depth) { + abort('readPixels is impossible, we are async GL'); + }; + this.pixelStorei = function(pname, param) { + commandBuffer.push(48, pname, param); + }; + this.depthMask = function(flag) { + commandBuffer.push(49, flag); + }; + this.depthRange = function(near, far) { + commandBuffer.push(50, near, far); + }; + this.blendFunc = function(sfactor, dfactor) { + commandBuffer.push(51, sfactor, dfactor); + }; + this.scissor = function(x, y, width, height) { + commandBuffer.push(52, x, y, width, height); + }; + this.colorMask = function(red, green, blue, alpha) { + commandBuffer.push(53, red, green, blue, alpha); + }; + this.lineWidth = function(width) { + commandBuffer.push(54, width); + }; + this.createFramebuffer = function() { + var id = nextId++; + commandBuffer.push(55, id); + return new WebGLFramebuffer(id); + }; + this.deleteFramebuffer = function(framebuffer) { + if (!framebuffer) return; + commandBuffer.push(56, framebuffer.id); + }; + this.bindFramebuffer = function(target, framebuffer) { + commandBuffer.push(57, target, framebuffer ? framebuffer.id : 0); + }; + this.framebufferTexture2D = function(target, attachment, textarget, texture, level) { + commandBuffer.push(58, target, attachment, textarget, texture ? texture.id : 0, level); + }; + this.checkFramebufferStatus = function(target) { + return this.FRAMEBUFFER_COMPLETE; // XXX totally wrong + }; + this.createRenderbuffer = function() { + var id = nextId++; + commandBuffer.push(59, id); + return new WebGLRenderbuffer(id); + }; + this.deleteRenderbuffer = function(renderbuffer) { + if (!renderbuffer) return; + commandBuffer.push(60, renderbuffer.id); + }; + this.bindRenderbuffer = function(target, renderbuffer) { + commandBuffer.push(61, target, renderbuffer ? renderbuffer.id : 0); + }; + this.renderbufferStorage = function(target, internalformat, width, height) { + commandBuffer.push(62, target, internalformat, width, height); + }; + this.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) { + commandBuffer.push(63, target, attachment, renderbuffertarget, renderbuffer ? renderbuffer.id : 0); + }; + //this.debugPrint = function(text) { // useful to interleave debug output properly with client GL commands + // commandBuffer.push(64, text); + //}; + + // Setup + var dropped = 0; + var average = 0; + var last = 0; + var meanDiff = 0; + var preMainLoop = Module['preMainLoop']; + Module['preMainLoop'] = function() { + /* + var now = Date.now(); + if (last > 0) { + var diff = now - last; + meanDiff = 0.95*meanDiff + 0.05*diff; + if (clientFrameId % 10 === 0) dump('server fps ' + (1000/meanDiff) + ' (ignoring client throttling)\n'); + } + last = now; + */ + if (preMainLoop) { + var ret = preMainLoop(); + if (ret === false) return ret; + } + // if too many frames in queue, skip a main loop iter + if (Math.abs(frameId - clientFrameId) >= 3) { + //dropped++; + //if (dropped % 10 === 0) dump('dropped: ' + [dropped, frameId, Math.round(100*dropped/(frameId + dropped)) + '%\n']); + return false; + } + }; + var postMainLoop = Module['postMainLoop']; + Module['postMainLoop'] = function() { + if (postMainLoop) postMainLoop(); + if (commandBuffer.length > 0) { + //average = (average + commandBuffer.length)/2; + //dump('buffer size: ' + Math.round(average) + '\n'); + postMessage({ target: 'gl', op: 'render', commandBuffer: commandBuffer }); + commandBuffer = []; + } + }; +} + +// share prefetched data among all instances + +WebGLWorker.prototype.prefetchedParameters = {}; +WebGLWorker.prototype.prefetchedExtensions = {}; + |