Substantial lag when updating canvas texture

I generate a dynamic sprite sheet consisting of images layered on top of each other (head, body, overlays, weapon, etc.). This allows the players to change their hats for instance at runtime, i.e.switch head layer.

Each image is 2048px² in dimension and is about 150kb in size. Since the order of layers is different for the front and back perspective of the sprite (e.g. weapon behind vs in front of body) I need two textures per sprite.

Given a test case of refreshing of 6 layers of images per sprite makes 12 images (2048px²) totalling 1800kb. In game, this could be a player switching to a secondary weapon. This happens in plain view.

The problem is this operation takes up to 1.5 seconds. Is this as more or less expected or is my use of the canvas texture flawed?

//non-production test code
_test() {
  console.time(1);
  
//layer order
  const TEMP_BACK = ["back", "weapon", "head"];//etc.
  const TEMP_ELSE = ["back", "body", "vest"];   //etc.
  
  const compoundTextureFront = this.__frontText;
  const compoundTextureBack = this.__backText;
  
  const f = this.$engine.anims.getFrameName();
  
  compoundTextureFront.clear();
  compoundTextureBack.clear();
  
//to be changed
  const spriteIds = {
    weapon:'1', 
    vest: '2', 
    head: '3',
    back: '4', 
    front: '5', 
    body:'6'
  };
  
  TEMP_ELSE.forEach((slot)=>{
    if(spriteIds[slot] !== undefined) {
      compoundTextureFront.draw(0,0, $scene.textures.get(spriteIds[slot]).getSourceImage());
    }
  });      
  
  compoundTextureFront.refresh();      
  
  TEMP_BACK.forEach((slot)=>{
    if(spriteIds[slot] !== undefined) {
      compoundTextureBack.draw(0,0, $scene.textures.get(spriteIds[slot]).getSourceImage());
    }
  });
  
  compoundTextureBack.refresh();      

  this.$engine.setTexture("new_texture", f);
  
  console.timeEnd(1);
}

It does seem long. But it may be the refresh.

One call to _test() is updating 2 textures, right?

How many draw() calls are there per _test()?

In the test case I have got 12 draw calls in total.

Double checked with console.logs.

Also, reducing calls to the minimum of 2 calls (i.e. one layer per texture) brings me down to ~300 - 500ms.

I guess it might be helpful to make an isolated test case. Please give me some time.

Are the images 2048 × 2048 px or much smaller?

Yes, the textures are all 2048px². Of course, in the animation software they are about 8 or so times bigger and I resize and pack them.

In the meantime I have created an isolated test case here: GitHub - Joe-Kerr/tempPhaserRenderLag

I cannot publish the actual textures but I have recreated them as far as possible. They are a bit smaller in file size. In the repo, I too render 2 textures each 6 frames. I get similar results:

Total: 1100 - 1200 ms
Per draw call (12): 70 - 100 ms
Per refresh call (2): 20 - 40 ms

Hold on, reading your reply a second time. Or do you mean “content” size? The real sprite sheets are work-in-progress and are only filled with “pixels” about 50% (I mean actual frames drawn). Coincidentally this is also the case for the repo because I could not find larger spritesheets.

Thanks. I guess that may be unavoidable given the number of textures and their size (dimensions). You could try with a RenderTexture but I’m not sure it will make a difference. :slightly_frowning_face: