title: The Fastest Way to Batch Calls in WebGL
body: <p>I'm trying to rewrite my canvas-based rendering for my 2d game engine. I've made good progress and can render textures to the webgl context fine, complete with scaling, rotation and blending. But my performance sucks. On my test laptop, I can get 30 fps in vanilla 2d canvas with 1,000 entities on screen at once; in WebGL, I get 30 fps with 500 entities on screen. I'd expect the situation to be reverse!</p>
  
  <p>I have a sneaking suspicion that the culprit is all this <code>Float32Array</code> buffer garbage I'm tossing around. Here's my render code:</p>
  
  <pre><code>// boilerplate code and obj coordinates
  
  // grab gl context
  var canvas = sys.canvas;
  var gl = sys.webgl;
  var program = sys.glProgram;
  
  // width and height
  var scale = sys.scale;
  var tileWidthScaled = Math.floor(tileWidth * scale);
  var tileHeightScaled = Math.floor(tileHeight * scale);
  var normalizedWidth = tileWidthScaled / this.width;
  var normalizedHeight = tileHeightScaled / this.height;
  
  var worldX = targetX * scale;
  var worldY = targetY * scale;
  
  this.bindGLBuffer(gl, this.vertexBuffer, sys.glWorldLocation);
  this.bufferGLRectangle(gl, worldX, worldY, tileWidthScaled, tileHeightScaled);
  
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, this.texture);
  
  var frameX = (Math.floor(tile * tileWidth) % this.width) * scale;
  var frameY = (Math.floor(tile * tileWidth / this.width) * tileHeight) * scale;
  
  // fragment (texture) shader
  this.bindGLBuffer(gl, this.textureBuffer, sys.glTextureLocation);
  this.bufferGLRectangle(gl, frameX, frameY, normalizedWidth, normalizedHeight);
  
  gl.drawArrays(gl.TRIANGLES, 0, 6);
  
  bufferGLRectangle: function (gl, x, y, width, height) {
      var left = x;
      var right = left + width;
      var top = y;
      var bottom = top + height;
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          left, top,
          right, top,
          left, bottom,
          left, bottom,
          right, top,
          right, bottom
      ]), gl.STATIC_DRAW);
  },
  
  bindGLBuffer: function (gl, buffer, location) {
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);
  },
  </code></pre>
  
  <p>And here's my simple test shaders (these are missing blending, scaling &amp; rotation):</p>
  
  <pre><code>// fragment (texture) shader
  precision mediump float;
  uniform sampler2D image;
  varying vec2 texturePosition;
  
  void main() {
      gl_FragColor = texture2D(image, texturePosition);
  }
  
  // vertex shader
  attribute vec2 worldPosition;
  attribute vec2 vertexPosition;
  
  uniform vec2 canvasResolution;
  varying vec2 texturePosition;
  
  void main() {
      vec2 zeroToOne = worldPosition / canvasResolution;
      vec2 zeroToTwo = zeroToOne * 2.0;
      vec2 clipSpace = zeroToTwo - 1.0;
  
      gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
      texturePosition = vertexPosition;
  }
  </code></pre>
  
  <p>Any ideas on how to get better performance? Is there a way to batch my drawArrays? Is there a way to cut down on the buffer garbage?</p>
  
  <p>Thanks!</p>