title: Custom webgl renderer slow. Are function.call()s innefficient for webgl?
body: <p>I've been writing my own renderer for a while now and I just about got the system running decently, but I am running into some speed issues.</p>
  <p>At about 1000 scene objects, the fps drops really fast and by 2000 objects, the max my laptop can get is 25 fps. I made the exact same scene with THREE and i get a constant 60fps which is really annoying and I'm not sure what to do.</p>
  <p>After creating a debug timer for myself, I disscovered that most of the lag is coming from assigning my attributes, the uniforms and also the draw call itself.</p>
  <p>In my pipeline i have a map of shaders and for each object using that shader, I get the required attributes and uniforms and then send the data over to the gpu.</p>
  <p>I have a feeling that it is the func.call(this.gl, args...) is what is slowing it down but I am really not sure.</p>
  <p>the code is below.</p>
  <pre><code>for (let [shader, mesh] of this.shaders) {
  
              shader.use(gl);
  
              let attributes = shader.attr;
              let uniforms   = shader.uni;
  
            
  
              for (let i = 0; i &lt; mesh.length; i++) {
  
  
                  const mesh_attr = mesh[i].attributes;
  
                  for (let key in attributes) {
  
                      if (!attributes.hasOwnProperty(key)) continue;
  
                      if (mesh_attr[key] === undefined || mesh_attr[key] === null) {
                          console.warn(`mesh ${mesh[i].uuid} does not have the attribute ${key}\nwill not render this object`);
                          continue;
                      }
  
  
                      const numComponents = mesh_attr[key].size;
                      const type          = FLOAT;
                      const normalize     = false;
                      const stride        = 0;
                      const offset        = 0;
  
                      gl.bindBuffer(ARRAY_BUFFER, mesh_attr[key].buffer);
  
                      gl.vertexAttribPointer(
                          attributes[key],
                          numComponents,
                          type,
                          normalize,
                          stride,
                          offset);
  
                      gl.enableVertexAttribArray(attributes[key]);
  
                  }
  
                  if (mesh[i].geometry.indexed === true) {
  
                      {
                          gl.bindBuffer(ELEMENT_ARRAY_BUFFER, mesh_attr.indices.buffer);
                      }
  
                  }
  
  
                  const mesh_uni = mesh[i].uniforms;
  
                  for (let key in uniforms) {
  
                      if (!uniforms.hasOwnProperty(key)) continue;
  
                      switch (key) {
  
                          case 'uModel':
                              uniforms[key].func.call(this.gl, uniforms[key].location, false, mesh[i].modelMatrix);
  
                              break;
                          case 'uProjection':
                              uniforms[key].func.call(this.gl, uniforms[key].location, false, projectionMatrix);
  
                              break;
                          case 'uView':
                              uniforms[key].func.call(this.gl, uniforms[key].location, false, viewMatrix);
                              break;
                          default:
                              if (uniforms[key].matrix) {
                                  uniforms[key].func.call(this.gl, uniforms[key].location, false, mesh_uni[key].data);
                              }
                              else {
                                  uniforms[key].func.call(this.gl, uniforms[key].location, mesh_uni[key].data);
                              }
                              break;
  
  
                      }
  
  
                  }
  
                  let vertexCount;
  
                  if (mesh[i].geometry.indexed === true) {
  
                      vertexCount = mesh[i].attributes.indices.data.length;
  
  
                      const type   = gl.UNSIGNED_SHORT;
                      const offset = 0;
                      gl.drawElements(mesh[i].material.drawMode, vertexCount, type, offset);
  
                  }
  
                  else {
  
  
                      vertexCount = mesh[i].attributes.aPosition.data.length / mesh[i].attributes.aPosition.size;
                      const type  = gl.UNSIGNED_SHORT;
  
                      gl.drawArrays(mesh[i].material.drawMode, vertexCount, type);
  
                  }
  
  
              }
  
  
          }
  </code></pre>
  <p>Does anyone know why im experiencing all this lag? I'm really not sure wht and I've been playing around with it for 2 days with no success. I'm not sure if its just my bad code :) or a weird bug in my code?</p>
  <p>Any help would be greatly appreciated.</p>
  <p>Also I am really sorry I couldn't think of an appropriate title so I put whatever and I dont think its very good.</p>