Skip to content
Snippets Groups Projects
Select Git revision
  • 8a368c069046f5eecc6de6219976e6b608c0c8eb
  • master default
  • neil
  • hpgl
  • sw-shawn-liu
  • ppa
  • fran
  • trotec-port
  • fs-hotfix
  • jake
  • ml-mods
  • fabmo-app
12 results

glsl_benchmark

Blame
  • glsl_benchmark 11.19 KiB
    //
    // benchmark
    //
    // Neil Gershenfeld 
    // (c) Massachusetts Institute of Technology 2016
    // 
    // This work may be reproduced, modified, distributed, performed, and 
    // displayed for any purpose, but must acknowledge the mods
    // project. Copyright is retained and must be preserved. The work is 
    // provided as is; no warranty is provided, and users accept all 
    // liability.
    //
    // closure
    //
    (function(){
    //
    // module globals
    //
    var mod = {}
    //
    // name
    //
    var name = 'glsl_benchmark'
    //
    // initialization
    //
    var init = function() {
       mod.terms.value = '1e8'
       }
    //
    // inputs
    //
    var inputs = {
       start:{type:'event',
          event:function(evt){
             benchmark()}}}
    //
    // outputs
    //
    var outputs = {
       }
    //
    // interface
    //
    var interface = function(div){
       mod.div = div
       var canvas = document.createElement('canvas');
       canvas.style.display = "none";
        div.appendChild(canvas)
       div.appendChild(document.createTextNode('terms to sum: '))
       var input = document.createElement('input')
          input.type = 'text'
          input.size = 6
          div.appendChild(input)
          mod.terms = input
       div.appendChild(document.createElement('br'))
       var btn = document.createElement('button')
          btn.style.padding = mods.ui.padding
          btn.style.margin = 1
          var text = document.createTextNode('calculate pi')
             mod.label = text
             btn.appendChild(text)
          btn.addEventListener('click',function() {
             benchmark()
             })
          mod.button = btn
          div.appendChild(btn)
       div.appendChild(document.createElement('br'))
       var text = document.createTextNode('value: ')
          div.appendChild(text)
          mod.value = text
       div.appendChild(document.createElement('br'))
       var text = document.createTextNode('time (s): ')
          div.appendChild(text)
          mod.time = text
       div.appendChild(document.createElement('br'))
       var text = document.createTextNode('Mflops: ')
          div.appendChild(text)
          mod.mflops = text
       }
    //
    // local functions
    //
    function benchmark() {
       mod.label.nodeValue = 'calculating';
       var numTerms = parseFloat(mod.terms.value);
    
    
        var output = calcPI(numTerms);
    
          mod.value.nodeValue = 'value: '+output.pi.toFixed(6);
          var sec = output.dt/1000
          mod.time.nodeValue = 'time (s): '+sec
          var mflops = 5*numTerms/(sec*1e6)
          mod.mflops.nodeValue = 'Mflops: '+mflops.toFixed(0)
          mod.label.nodeValue = 'calculate pi'
       }
    
        var vertexShaderSource = "" +
            "attribute vec2 a_position;"+
            "void main() { "+
               "gl_Position = vec4(a_position, 0, 1);"+
            "}"
    
        var fragmentShaderSource = "" +
            "precision mediump float;"+
            "uniform float u_matrixDim;"+
            "uniform float u_offset;"+
            "" +
            "float shift_right (float v, float amt) {" +
                "v = floor(v) + 0.5;" +
                "return floor(v / exp2(amt));" +
            "}"+
            "float shift_left (float v, float amt) {" +
                "return floor(v * exp2(amt) + 0.5);" +
            "}"+
            "float mask_last (float v, float bits) {"+
                "return mod(v, shift_left(1.0, bits));"+
            "}"+
            "float extract_bits (float num, float from, float to) {"+
                "from = floor(from + 0.5); to = floor(to + 0.5);"+
                "return mask_last(shift_right(num, from), to - from);"+
            "}"+
            "vec4 encode_float (float val) {"+
                "if (val == 0.0) return vec4(0, 0, 0, 0);"+
                "float sign = val > 0.0 ? 0.0 : 1.0;"+
                "val = abs(val);"+
                "float exponent = floor(log2(val));"+
                "float biased_exponent = exponent + 127.0;" +
                "float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0;"+
                "float t = biased_exponent / 2.0;"+
                "float last_bit_of_biased_exponent = fract(t) * 2.0;"+
                "float remaining_bits_of_biased_exponent = floor(t);"+
                "float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0;" +
                "float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0;" +
                "float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0;" +
                "float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0;" +
                "return vec4(byte4, byte3, byte2, byte1);" +
            "}"+
            "" +
            "void main(){" +
                "vec2 fragCoord = gl_FragCoord.xy;"+
                "float index = fragCoord.x + 0.5 + (fragCoord.y-0.5)*u_matrixDim + u_offset;"+
                "gl_FragColor = encode_float(0.5/((index-0.75)*(index-0.25)));"+
            "}";
    
    /**
     * Created by ghassaei on 2/20/16.
     */
    
    function calcPI(numTerms) {
    
        // Get A WebGL context
        var canvas = document.getElementsByTagName("canvas")[0];
        var gl = canvas.getContext("webgl", {antialias:false}) || canvas.getContext("experimental-webgl", {antialias:false});
        if (!gl) {
            alert('Could not initialize WebGL, try another browser');
            return;
        }
    
        gl.disable(gl.DEPTH_TEST);
        gl.getExtension('OES_texture_float');
    
        var matrixDim = 1024;
        var matrixSize = matrixDim*matrixDim;
        gl.viewport(0, 0, matrixDim, matrixDim);
        canvas.clientWidth = matrixDim;
        canvas.clientHeight = matrixDim;
    
        var numMatrices = Math.ceil(numTerms/matrixSize);
    
    
        var offsets = [];
        for (var i=0;i<numMatrices;i++){
            offsets.push(matrixSize*i);
        }
    
        //setup a GLSL program
        var piProgram = createProgramFromScripts(gl, vertexShaderSource, fragmentShaderSource);
        gl.useProgram(piProgram);
        loadVertexData(gl, piProgram);
    
        var piTextures = [];
        var piFrameBuffers = [];
        for (var i=0;i<numMatrices;i++){
            var piTexture = makeTexture(gl, matrixDim, matrixDim, gl.UNSIGNED_BYTE, null);
            var piFrameBuffer = makeFrameBuffer(gl, piTexture);
            piTextures.push(piTexture);
            piFrameBuffers.push(piFrameBuffer);
        }
        gl.uniform1f(gl.getUniformLocation(piProgram, "u_matrixDim"), matrixDim);
        var offsetLocation = gl.getUniformLocation(piProgram, "u_offset");
    
        var pixels = new Uint8Array(matrixSize*4);
    
        var tstart = Date.now();
    
        gl.useProgram(piProgram);
        for (var i=0;i<numMatrices;i++){
            gl.uniform1f(offsetLocation, offsets[i]);
            gl.bindFramebuffer(gl.FRAMEBUFFER, piFrameBuffers[i]);
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);//draw to framebuffer
        }
    
        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
    
            var pi = 0;
            for (var i=0;i<numMatrices;i++){
                gl.bindFramebuffer(gl.FRAMEBUFFER, piFrameBuffers[i]);
                gl.readPixels(0, 0, matrixDim, matrixDim, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
                var parsedPixels = new Float32Array(pixels.buffer);
                for (var j=0;j<parsedPixels.length;j++){
                    pi += parsedPixels[j];
                }
            }
            var tend = Date.now();
    
            return {dt:tend-tstart, pi:pi, terms:pixels.length};
        }
    }
    
    
    
    function loadVertexData(gl, program) {
       gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
       gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -1,-1, 1,-1, -1, 1, 1, 1]), gl.STATIC_DRAW);
    
        // look up where the vertex data needs to go.
       var positionLocation = gl.getAttribLocation(program, "a_position");
       gl.enableVertexAttribArray(positionLocation);
       gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    }
    
    function makeFrameBuffer(gl, texture){
        var framebuffer = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
        return framebuffer;
    }
    
    function makeTexture(gl, width, height, type, data){
    
        var texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, texture);
    
        // Set the parameters so we can render any size image.
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, type, data);
    
        //gl.bindTexture(gl.TEXTURE_2D, null);
    
        return texture;
    }
    
    
    //from http://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html
    
    /**
     * Creates and compiles a shader.
     *
     * @param {!WebGLRenderingContext} gl The WebGL Context.
     * @param {string} shaderSource The GLSL source code for the shader.
     * @param {number} shaderType The type of shader, VERTEX_SHADER or
     *     FRAGMENT_SHADER.
     * @return {!WebGLShader} The shader.
     */
    function compileShader(gl, shaderSource, shaderType) {
      // Create the shader object
      var shader = gl.createShader(shaderType);
    
      // Set the shader source code.
      gl.shaderSource(shader, shaderSource);
    
      // Compile the shader
      gl.compileShader(shader);
    
      // Check if it compiled
      var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
      if (!success) {
        // Something went wrong during compilation; get the error
        throw "could not compile shader:" + gl.getShaderInfoLog(shader);
      }
    
      return shader;
    }
    
    /**
     * Creates a program from 2 shaders.
     *
     * @param {!WebGLRenderingContext) gl The WebGL context.
     * @param {!WebGLShader} vertexShader A vertex shader.
     * @param {!WebGLShader} fragmentShader A fragment shader.
     * @return {!WebGLProgram} A program.
     */
    function createProgram(gl, vertexShader, fragmentShader) {
      // create a program.
      var program = gl.createProgram();
    
      // attach the shaders.
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
    
      // link the program.
      gl.linkProgram(program);
    
      // Check if it linked.
      var success = gl.getProgramParameter(program, gl.LINK_STATUS);
      if (!success) {
          // something went wrong with the link
          throw ("program filed to link:" + gl.getProgramInfoLog (program));
      }
    
      return program;
    }
    
    /**
     * Creates a shader from the content of a script tag.
     *
     * @param {!WebGLRenderingContext} gl The WebGL Context.
     * @param {string} scriptId The id of the script tag.
     * @param {string} opt_shaderType. The type of shader to create.
     *     If not passed in will use the type attribute from the
     *     script tag.
     * @return {!WebGLShader} A shader.
     */
    function createShaderFromScript(gl, shaderSource, shaderType) {
      // look up the script tag by id.
      //var shaderScript = document.getElementById(scriptId);
      //if (!shaderScript) {
      //  throw("*** Error: unknown script element" + scriptId);
      //}
      //
      //// extract the contents of the script tag.
      //var shaderSource = shaderScript.text;
    
      return compileShader(gl, shaderSource, shaderType);
    }
    
    /**
     * Creates a program from 2 script tags.
     *
     * @param {!WebGLRenderingContext} gl The WebGL Context.
     * @param {string} vertexShaderId The id of the vertex shader script tag.
     * @param {string} fragmentShaderId The id of the fragment shader script tag.
     * @return {!WebGLProgram} A program
     */
    function createProgramFromScripts(
        gl, vertexSource, fragmentSource) {
      var vertexShader = createShaderFromScript(gl, vertexSource, gl.VERTEX_SHADER);
      var fragmentShader = createShaderFromScript(gl, fragmentSource, gl.FRAGMENT_SHADER);
      return createProgram(gl, vertexShader, fragmentShader);
    }
    
    
    
    
    return ({
       mod:mod,
       name:name,
       init:init,
       inputs:inputs,
       outputs:outputs,
       interface:interface
       })
    }())