Search Unity

Question DrawMeshInstanced no more limit count?

Discussion in 'General Graphics' started by pan4ezzz, May 14, 2023.

  1. pan4ezzz

    pan4ezzz

    Joined:
    Jul 9, 2017
    Posts:
    19
    Hi Unity!
    I use 2022.2.12, and just try Graphics.DrawMeshInstanced() w/ million instances count and it work!

    I see some guard inside:
    Code (CSharp):
    1.  
    2. if (count < 0 || count > Mathf.Min(kMaxDrawMeshInstanceCount, matrices.Length))
    3. {
    4.     throw new ArgumentOutOfRangeException("count", $"Count must be in the range of 0 to {Mathf.Min(kMaxDrawMeshInstanceCount, matrices.Length)}.");
    5. }
    6.  
    But kMaxDrawMeshInstanceCount definitely not 1023, what is this miracle?
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    Hi!
    We changed some internals in 2022, so it now uses 20 bits for array size.
    You are still limited by the constant buffer size (65536 bytes) if you're using them for instanced data, though.
     
    pan4ezzz likes this.
  3. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    838
    It wouldve been so nice if kMaxDrawMeshInstanceCount was public. That way i could just fill batches until that, achieving max performance for all platforms.

    Luckily with some InternalsVisibleTo we can get to it. In my Windows editor the max seems to be 1048575.
     
  4. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    As I said, it now uses 20 bits for the array size. Which gives 2^20 - 1 = 1048575.
     
    TJHeuvel-net likes this.
  5. Andrew900460

    Andrew900460

    Joined:
    Aug 9, 2017
    Posts:
    40
    I am curious what your code looks like for how you are using Graphics.DrawMeshInstanced() in your case.
    For me, I am using CommandBuffer.DrawMeshInstanced() to draw a bunch of quad meshes to a render texture.
    But because of the api, I have to give it an array of Matrix4x4, even though I only use the x and y translation values in the matrix; All the other matrix values are not used (zero or one).

    From what I understand from what @aleksandrk said, the "max buffer size" for instanced is "still" 65536 bytes.
    And since CommandBuffer.DrawMeshInstanced() requires an array of 4x4 Matrices (16 floats = 64 bytes), that would mean that the total possible instances is 65536/64 = 1024. Which is indeed the same as before.

    But then Aleks and @TJHeuvel-net mention the value "1048575" for the array size. So the total bytes of the internal buffer??? If it was that value, then I would be able pass in an array of matrics that's about 16,383 long, instead of 1023 long, if that is the case.

    TLDR:

    But that is why I'm just curious how you are using DrawMeshInstanced if you are able to have a lot more than 1023 instances (example code pls?). I assume you are using it in a very different way than I am. I don't know a whole lot about the other ways at which instancing can be used. I only learned eanough to use it in the "basic" fasion.
    But I know you can also use ComputeBuffer/GraphicsBuffer with DrawMeshInstancedIndirect. I just haven't had the time to try and understand how to use it properly.
    I am also currently working in 2021.3.9.f1 So I may not be able to get/test these benefits yet.

    But I'd like to learn about this for my future reference.
     
  6. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    @Andrew900460 There's a byte size limit for the size of the constant buffer. On most platforms it's 65536 bytes, but some Android devices support only up to 16384 bytes.
    The 2^20 array size is the limitation of the Unity-side internal buffer that's used for storing the data.

    If you need more matrices, you can split them into several separate constant buffers manually and reconstruct the matrix in the shader.