Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Strategies for improving performance - any ideas?

Discussion in 'Editor & General Support' started by larku, May 25, 2017.

  1. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    ---------------------------------------------------------------------------

    TL;DR; I think I've got fill rate issues on some Android devices using a 512x512 atlas drawing 150 tiles (mix of 50 different textures - all in the one atlas) using batching (around 6 or so batches due to indicies count). How would you address this? What are my options?

    ---------------------------------------------------------------------------

    Analysis of why I think it's a fill rate issue follows:

    My scenario:
    • scene has 150 simple objects (tiles), approx 100 verts;
    • each tile can have 1 of 50 textures assigned to it;
    • each tile has a pre-baked alpha shadow under it (attached as child to tile), it's a plane with alpha texture;
    • scripts are no concern (Behaviour.update is about 0.05ms);
    • shader is a modified matcap shader ( https://www.assetstore.unity3d.com/en/?gclid=CO#!content/8221 ); and
    • test device is (intentionally old and nasty) Galaxy Note 10.1 (aiming to support this or above). I'm, also targeting iOS so any solution needs to be equally valid there too.
    With no tweaking this will cause over 400 draw calls - obviously not ideal for mobile.

    My original 50 textures are 74x106 pixels. I set the import settings to "to nearest" which gives me textures of 64x128.

    What I've tried:

    First attack at this is to get some batching happening: I created a 512x512 atlas and 50 different "tile" models with the UVs mapped to the correct image in the atlas;
    • enable dynamic batching
    This works great in reducing draw calls, from > 400 down to about 6 (nice!) but on the test device this caused some serious CPU load creating the batches each frame - about 23ms when calling Batch.DrawDynamic which is obviously not good (see image):

    perf1.png

    This same call is sub ms on a more modern device (eg OnePlus One) - is this expected?

    I end up with about 6 batches due to indicies limits being hit (32k indicies per batch).

    So, my next idea was to use StaticBatchingUtility.Combine(rootOfMyObjects); This will come with it's own set of issues as I need to remove tiles from the board as they are eliminated by the player and also change some materials as required. I assume I can keep a copy of the real set of tiles and regenerate the static batch as needed (??). I can't use the compile time batching as the tile layouts are generated dynamically (there are thousands of different layouts).

    BUT, replacing the Dynamic Batching with Static batching (as described above) produces a profile like:

    perf2.png


    So static batching removed the CPU load and is now exposing the GPU load.

    Trial and error suggests that the issue is the 512x512 atlas being drawn to a batch (4-6 batches depending) of tiles (150 or so).. Reducing the atlas to 128x128 (way too low and is only useful for testing) I'm able to get 60fps or close (15 - 16ms on average).

    I expect this is referred to as fill rate (??) and it seems I'm pushing it too far..

    So what are the best practices for working around these limitations? How should I proceed?

    I've had a few ideas and each comes with it's own set of issues:

    • Split the atlas into sets of smaller atlases (will this even help?). I estimate that at 128x128 I'd need something like 16 atlases to get acceptable quality and I cop 16 drawcalls minimum (which may be workable, since that'd still be under 40 drawcalls when including the rest of the sceene (UI, env, etc)); or
    • Render the tiles to a render texture and display that instead - but this becomes troublesome as I need to do effects on the tiles on the board as they're selected, etc, as such it'll be creating render textures often and I'd need to remove tiles also, so lots of recreating render textures. I'd also need a render texture that will fill the screen, which may become troublesome. This "idea" seemed good at first but then looking at all the other issues/complications it brings, it's not something I feel is practical and even if I get it working might just move the performance issue from one place to another.
    Do I have other options? What would you do? Am I missing an obvious solution?

    I've only got 1 hair left on my head that's not been pulled out over this, so if you've got any ideas please shoot before I pluck that last one!!
     
    Last edited: May 25, 2017