WeblGL - Drawing Tons of moving Images with Little CPU
===

I've made a game using the Canvas element and with 300+ images being drawn every frame I am forced to make it run at <20 fps and it takes 60+% CPU:

So I guess my best option is to switch to WebGL. I've been scavenging the web, looking for tutorials and examples. It's kinda complex stuff but I managed to hack together a working source.

    <!-- Licensed under a BSD license. See license.html for license -->
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>WebGL - 2D Image</title>
    <link type="text/css" href="http://games.greggman.com/downloads/examples/webgl/resources/webgl-tutorials.css" rel="stylesheet" />
    <script type="text/javascript" src="http://games.greggman.com/downloads/examples/webgl/resources/webgl-utils.js"></script>
    <script>
    window.onload = main;
    
    function main() {
      image = new Image();
      image.src = "http://games.greggman.com/downloads/examples/webgl/resources/leaves.jpg";  // MUST BE SAME DOMAIN!!!
      image.onload = function() {
        setUp();
    	setInterval(function(){
    		x1 += 1;
    		y1 += 1
    		for (i = 0; i < 30; i++) {
    			for (e = 0; e < 10; e++) {
    				//render(image, x1+i*5, y1+e*5);
    				gl.bindTexture(gl.TEXTURE_2D, texture);
    
     				 // Set a rectangle the same size as the image.
      				setRectangle(gl, x1+i*5, y1+e*5, image.width, image.height);
    
     			 	// Draw the rectangle.
     				 gl.drawArrays(gl.TRIANGLES, 0, 6);
    			}
    		}
    	},1000/60);
      }
    }
    var x1 = 0;
    var y1 = 0;
    var image;
    var canvas;
    var gl;
    var texture;
    function setUp() {
      canvas = document.getElementById("canvas");
      gl = getWebGLContext(canvas);
    	// setup GLSL program
      vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
      fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
      program = createProgram(gl, [vertexShader, fragmentShader]);
      gl.useProgram(program);
    
     	// lookup uniforms
      var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    
      // set the resolution
      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
    
    // Create a texture.
      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);
    
      // Upload the image into the texture.
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    
     // look up where the vertex data needs to go.
      var positionLocation = gl.getAttribLocation(program, "a_position");
      var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
    
      // provide texture coordinates for the rectangle.
      var texCoordBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          0.0,  0.0,
          1.0,  0.0,
          0.0,  1.0,
          0.0,  1.0,
          1.0,  0.0,
          1.0,  1.0]), gl.STATIC_DRAW);
      gl.enableVertexAttribArray(texCoordLocation);
      gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
    
      
    
      
    
      // Create a buffer for the position of the rectangle corners.
      var buffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.enableVertexAttribArray(positionLocation);
      gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    }
    
    function render(image, x, y) {
      
    }
    
    function randomInt(range) {
      return Math.floor(Math.random() * range);
    }
    
    function setRectangle(gl, x, y, width, height) {
      var x1 = x;
      var x2 = x + width;
      var y1 = y;
      var y2 = y + height;
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
         x1, y1,
         x2, y1,
         x1, y2,
         x1, y2,
         x2, y1,
         x2, y2]), gl.STATIC_DRAW);
    }
    
    </script>
    <!-- vertex shader -->
    <script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    
    uniform vec2 u_resolution;
    
    varying vec2 v_texCoord;
    
    void main() {
       // convert the rectangle from pixels to 0.0 to 1.0
       vec2 zeroToOne = a_position / u_resolution;
    
       // convert from 0->1 to 0->2
       vec2 zeroToTwo = zeroToOne * 2.0;
    
       // convert from 0->2 to -1->+1 (clipspace)
       vec2 clipSpace = zeroToTwo - 1.0;
    
       gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
    
       // pass the texCoord to the fragment shader
       // The GPU will interpolate this value between points.
       v_texCoord = a_texCoord;
    }
    </script></script>
    <!-- fragment shader -->
    <script id="2d-fragment-shader" type="x-shader/x-fragment">
    precision mediump float;
    
    // our texture
    uniform sampler2D u_image;
    
    // the texCoords passed in from the vertex shader.
    varying vec2 v_texCoord;
    
    void main() {
       gl_FragColor = texture2D(u_image, v_texCoord);
    }
    </script>
    </head>
    <body>
    <canvas id="canvas" width="400" height="300"></canvas>
    </body>
    </html>

It draws 300 images but takes only 1/2 the CPU of using the normal canvas. Now that's not too bad but it's still not good enough.
Am I doing something wrong or unnecessary? Is there a way I can ease of the CPU by doing calculations in the GPU or caching them?
I've researched in shaders and would it be possible to use a shader to store textures and coordinates and just input an array to the shader to set location points of each image I need to draw?

Thanks,
I hope there's an easy solution to this madness.