Internal Documentation: kernel.js (webgl)

This commit is contained in:
Abhishek Soni 2017-06-30 19:55:59 +05:30
parent f3e51e30e5
commit fe78eb5d9e
2 changed files with 335 additions and 19 deletions

View File

@ -9,25 +9,39 @@ const kernelString = require('./kernel-string');
///
/// Class: WebGLKernel
///
/// Kernel Implementation for WebGL.
/// This builds the shaders and runs them on the GPU,
/// the outputs the result back as float(enabled by default) and Texture.
///
/// Extends:
/// KernelBase
///
/// Parameters:
/// textureCache - {Object} - webGl Texture cache
/// threadDim - {Object} - The thread dimensions, x, y and z
/// programUniformLocationCache - {Object} - Location of program variables in memory
/// framebuffer - {Object} - Webgl frameBuffer
/// buffer - {Object} - WebGL buffer
/// program - {Object} - The webGl Program
/// functionBuilder - {Object} - Function Builder instance bound to this Kernel
/// outputToTexture - {Boolean} - Set output type to Texture, instead of float
/// endianness - {String} - Endian information like Little-endian, Big-endian.
/// paramTypes - {Array} - Types of parameters sent to the Kernel
/// argumentsLength - {Number} - Number of parameters sent to the Kernel
/// compiledFragShaderString - {String} - Compiled fragment shader string
/// compiledVertShaderString - {String} - Compiled Vertical shader string
///
module.exports = class WebGLKernel extends KernelBase {
_getFragShaderArtifactMap(args) {
return {
HEADER: this._getHeaderString(),
LOOP_MAX: this._getLoopMaxString(),
CONSTANTS: this._getConstantsString(),
DECODE32_ENDIANNESS: this._getDecode32EndiannessString(),
ENCODE32_ENDIANNESS: this._getEncode32EndiannessString(),
GET_WRAPAROUND: this._getGetWraparoundString(),
GET_TEXTURE_CHANNEL: this._getGetTextureChannelString(),
GET_TEXTURE_INDEX: this._getGetTextureIndexString(),
GET_RESULT: this._getGetResultString(),
MAIN_PARAMS: this._getMainParamsString(args),
MAIN_CONSTANTS: this._getMainConstantsString(),
KERNEL: this._getKernelString(),
MAIN_RESULT: this._getMainResultString()
};
}
//
// [Constructor]
//
///
/// Function: WebGLKernel
///
/// Instantiates properties to the WebGl Kernel.
///
constructor(fnString, settings) {
super(fnString, settings);
this.textureCache = {};
@ -50,6 +64,13 @@ module.exports = class WebGLKernel extends KernelBase {
if (!this._webGl) this._webGl = utils.initWebGl(this.canvas);
}
///
/// Function: validateOptions
///
/// Validate options related to Kernel, such as
/// floatOutputs and Textures, texSize, dimensions,
/// graphical output.
///
validateOptions() {
const isReadPixel = utils.isFloatReadPixelsSupported;
if (this.floatTextures === true && !utils.OES_texture_float) {
@ -97,6 +118,13 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: build
///
/// Builds the Kernel, by compiling Fragment and Vertical Shaders,
/// and instantiates the program.
///
build() {
this.validateOptions();
this.setupParams(arguments);
@ -145,12 +173,24 @@ module.exports = class WebGLKernel extends KernelBase {
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
gl.linkProgram(program);
this.framebuffer = this._webGl.createFramebuffer();
this.framebuffer = gl.createFramebuffer();
this.framebuffer.width = this.texSize[0];
this.framebuffer.height = this.texSize[1];
return this;
}
///
/// Function: run
///
/// Run the kernel program, and send the output to renderOutput
///
/// This method calls a helper method *renderOutput* to return the result.
///
/// Returns:
/// Result {Object} The final output of the program, as float, and as Textures for reuse.
///
///
run() {
if (this.program === null) {
this.build.apply(this, arguments);
@ -274,6 +314,23 @@ module.exports = class WebGLKernel extends KernelBase {
return this.renderOutput(outputTexture);
}
///
/// Function: renderOutput
///
///
/// Helper function to return webGl function's output.
/// Since the program runs on GPU, we need to get the
/// output of the program back to CPU and then return them.
///
/// *Note*: This should not be called directly.
///
/// Parameters:
/// outputTexture Output Texture returned by webGl program
///
/// Returns:
/// result {Object|Array}
///
///
renderOutput(outputTexture) {
const texSize = this.texSize;
const gl = this._webGl;
@ -307,18 +364,59 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: getOutputTexture
///
/// This uses *getTextureCache* to get the Texture Cache of the Output
///
/// Returns:
/// Ouptut Texture Cache
///
getOutputTexture() {
return this.getTextureCache('OUTPUT');
}
///
/// Function: getArgumentTexture
///
/// This uses *getTextureCache** to get the Texture Cache of the argument supplied
///
/// Parameters:
/// name {String} Name of the argument
///
/// Returns:
/// Texture cache for the supplied argument
///
getArgumentTexture(name) {
return this.getTextureCache(`ARGUMENT_${ name }`);
}
///
/// Function: getSubKernelTexture
///
/// This uses *getTextureCache* to get the Texture Cache of the sub-kernel
///
/// Parameters:
/// name {String} Name of the subKernel
///
/// Returns:
/// Texture cache for the subKernel
///
getSubKernelTexture(name) {
return this.getTextureCache(`SUB_KERNEL_${ name }`);
}
///
/// Function: getTextureCache
///
/// Returns the Texture Cache of the supplied parameter (can be kernel, sub-kernel or argument)
///
/// Parameters:
/// name {String} Name of the subkernel, argument, or kernel.
///
/// Returns:
/// Texture cache
///
getTextureCache(name) {
if (this.outputToTexture) {
// Don't retain a handle on the output texture, we might need to render on the same texture later
@ -330,6 +428,15 @@ module.exports = class WebGLKernel extends KernelBase {
return this.textureCache[name] = this._webGl.createTexture();
}
///
/// Function: setupParams
///
/// Setup the parameter types for the parameters
/// supplied to the Kernel function
///
/// Parameters:
/// args {Array} The actual parameters sent to the Kernel
///
setupParams(args) {
const paramTypes = this.paramTypes = [];
for (let i = 0; i < args.length; i++) {
@ -339,6 +446,13 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: getUniformLocation
///
/// Return WebGlUniformLocation for various variables
/// related to webGl program, such as user-defiend variables,
/// as well as, dimension sizes, etc.
///
getUniformLocation(name) {
let location = this.programUniformLocationCache[name];
if (!location) {
@ -348,6 +462,47 @@ module.exports = class WebGLKernel extends KernelBase {
return location;
}
///
/// Function: _getFragShaderArtifactMap
///
/// Generate Shader artifacts for the kernel program.
/// The final object contains HEADER, KERNEL, MAIN_RESULT, and others.
///
/// Parameters:
/// args {Array} The actual parameters sent to the Kernel
///
/// Returns:
/// {Object} An object containing the Shader Artifacts(CONSTANTS, HEADER, KERNEL, etc.)
///
_getFragShaderArtifactMap(args) {
return {
HEADER: this._getHeaderString(),
LOOP_MAX: this._getLoopMaxString(),
CONSTANTS: this._getConstantsString(),
DECODE32_ENDIANNESS: this._getDecode32EndiannessString(),
ENCODE32_ENDIANNESS: this._getEncode32EndiannessString(),
GET_WRAPAROUND: this._getGetWraparoundString(),
GET_TEXTURE_CHANNEL: this._getGetTextureChannelString(),
GET_TEXTURE_INDEX: this._getGetTextureIndexString(),
GET_RESULT: this._getGetResultString(),
MAIN_PARAMS: this._getMainParamsString(args),
MAIN_CONSTANTS: this._getMainConstantsString(),
KERNEL: this._getKernelString(),
MAIN_RESULT: this._getMainResultString()
};
}
///
/// Function: _addArgument
///
/// Adds kernel parameters to the Argument Texture,
/// binding it to the webGl instance, etc.
///
/// Parameters:
/// value {Array|Texture|Number} The actual argument supplied to the kernel
/// type {String} Type of the argument
/// name {String} Name of the argument
///
_addArgument(value, type, name) {
const gl = this._webGl;
const argumentTexture = this.getArgumentTexture(name);
@ -429,6 +584,15 @@ module.exports = class WebGLKernel extends KernelBase {
this.argumentsLength++;
}
///
/// Function: _getHeaderString
///
/// Get the header string for the program.
/// This returns an empty string if no sub-kernels are defined.
///
/// Returns:
/// result {String}
///
_getHeaderString() {
return (
this.subKernels !== null || this.subKernelProperties !== null ?
@ -438,6 +602,14 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getLoopMaxString
///
/// Get the maximum loop size String.
///
/// Returns:
/// result {String}
///
_getLoopMaxString() {
return (
this.loopMaxIterations ?
@ -446,6 +618,16 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getConstantsString
///
/// Generate transpiled glsl Strings for constant parameters sent to a kernel
///
/// They can be defined by *hardcodeConstants*
///
/// Returns:
/// result {String}
///
_getConstantsString() {
const result = [];
const threadDim = this.threadDim;
@ -465,6 +647,14 @@ module.exports = class WebGLKernel extends KernelBase {
return this._linesToString(result);
}
///
/// Function: _getTextureCoordinate
///
/// Get texture coordinate string for the program
///
/// Returns:
/// result {String}
///
_getTextureCoordinate() {
const names = this.subKernelOutputVariableNames;
if (names === null || names.length < 1) {
@ -474,6 +664,14 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: _getDecode32EndiannessString
///
/// Get Decode32 endianness string for little-endian and big-endian
///
/// Returns:
/// result {String}
///
_getDecode32EndiannessString() {
return (
this.endianness === 'LE' ?
@ -482,6 +680,14 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getEncode32EndiannessString
///
/// Get Encode32 endianness string for little-endian and big-endian
///
/// Returns:
/// result {String}
///
_getEncode32EndiannessString() {
return (
this.endianness === 'LE' ?
@ -490,6 +696,9 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getGetWraparoundString
///
_getGetWraparoundString() {
return (
this.wraparound ?
@ -498,6 +707,9 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getGetTextureChannelString
///
_getGetTextureChannelString() {
if (!this.floatTextures) return '';
@ -507,6 +719,13 @@ module.exports = class WebGLKernel extends KernelBase {
]);
}
///
/// Function: _getGetTextureIndexString
///
/// Get generic texture index string, if floatTextures flag is true.
///
/// > ' index = float(int(index)/4);\n'
///
_getGetTextureIndexString() {
return (
this.floatTextures ?
@ -515,6 +734,9 @@ module.exports = class WebGLKernel extends KernelBase {
);
}
///
/// Function: _getGetResultString
///
_getGetResultString() {
if (!this.floatTextures) return ' return decode32(texel);\n';
return this._linesToString([
@ -525,6 +747,17 @@ module.exports = class WebGLKernel extends KernelBase {
]);
}
///
/// Function: _getMainParamsString
///
/// Generate transpiled glsl Strings for user-defined parameters sent to a kernel
///
/// Parameters:
/// args {Array} The actual parameters sent to the Kernel
///
/// Returns:
/// result {String}
///
_getMainParamsString(args) {
const result = [];
const paramTypes = this.paramTypes;
@ -565,6 +798,13 @@ module.exports = class WebGLKernel extends KernelBase {
}
return this._linesToString(result);
}
///
/// Function: _getMainConstantsString
///
/// Returns:
/// Texture cache
///
_getMainConstantsString() {
const result = [];
if (this.constants) {
@ -581,6 +821,15 @@ module.exports = class WebGLKernel extends KernelBase {
}
return this._linesToString(result);
}
///
/// Function: _getKernelString
///
/// Get Kernel program string (in *glsl*) for a kernel.
///
/// Returns:
/// result {String}
///
_getKernelString() {
const result = [];
const names = this.subKernelOutputVariableNames;
@ -607,6 +856,15 @@ module.exports = class WebGLKernel extends KernelBase {
return this._linesToString(result) + this.functionBuilder.getPrototypeString('kernel');
}
///
/// Function: _getMainResultString
///
/// Get main result string with checks for floatOutput, graphical, subKernelsOutputs, etc.
///
/// Returns:
/// result {String}
///
_getMainResultString() {
const names = this.subKernelOutputVariableNames;
const result = [];
@ -662,6 +920,15 @@ module.exports = class WebGLKernel extends KernelBase {
return this._linesToString(result);
}
///
/// Function: _linesToString
///
/// Parameters:
/// lines {Array} An Array of strings
///
/// Returns:
/// Single combined String, seperated by *\n*
///
_linesToString(lines) {
if (lines.length > 0) {
return lines.join(';\n') + ';\n';
@ -670,6 +937,16 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: _replaceArtifacts
///
/// Parameters:
/// src {String} Name of the subkernel, argument, or kernel.
/// map {String} Name of the subkernel, argument, or kernel.
///
/// Returns:
/// Texture cache
///
_replaceArtifacts(src, map) {
return src.replace(/[ ]*__([A-Z]+[0-9]*([_]?[A-Z])*)__;\n/g, (match, artifact) => {
if (map.hasOwnProperty(artifact)) {
@ -679,6 +956,11 @@ module.exports = class WebGLKernel extends KernelBase {
});
}
///
/// Function: _addKernels
///
/// Adds all the sub-kernels supplied with this Kernel instance.
///
_addKernels() {
const builder = this.functionBuilder;
const gl = this._webGl;
@ -728,6 +1010,19 @@ module.exports = class WebGLKernel extends KernelBase {
}
}
///
/// Function: _getFragShaderString
///
/// Get the fragment shader String.
/// If the String hasn't been compiled yet,
/// then this method compiles it as well
///
/// Parameters:
/// args {Array} The actual parameters sent to the Kernel
///
/// Returns:
/// {String} Fragment Shader string
///
_getFragShaderString(args) {
if (this.compiledFragShaderString !== null) {
return this.compiledFragShaderString;
@ -735,6 +1030,17 @@ module.exports = class WebGLKernel extends KernelBase {
return this.compiledFragShaderString = this._replaceArtifacts(fragShaderString, this._getFragShaderArtifactMap(args));
}
///
/// Function: _getVertShaderString
///
/// Get the vertical shader String
///
/// Parameters:
/// args {Array} The actual parameters sent to the Kernel
///
/// Returns:
/// {String} Vertical Shader string
///
_getVertShaderString(args) {
if (this.compiledVertShaderString !== null) {
return this.compiledVertShaderString;
@ -743,6 +1049,11 @@ module.exports = class WebGLKernel extends KernelBase {
return this.compiledVertShaderString = vertShaderString;
}
///
/// Function: toString
///
/// Returns the *pre-compiled* Kernel as a JS Object String, that can be reused.
///
toString() {
return kernelString(this);
}

5
src/texture.js vendored
View File

@ -1,4 +1,5 @@
let gpu = null;
///
/// Class: Texture
///
@ -11,6 +12,8 @@ module.exports = class Texture {
this.webGl = webGl;
}
///
/// Function: toArray
///
/// Converts the Texture into a JavaScript Array.
///
@ -27,6 +30,8 @@ module.exports = class Texture {
return copy(this.texture);
}
///
/// Function: delete
///
/// Deletes the Texture.
///
delete() {