Search Unity

  1. We would like to hear your feedback about Unity and our products. Click here for more information.
    Dismiss Notice

Fastest way to fill/remove TransformAccessArray?

Discussion in 'Data Oriented Technology Stack' started by Karnsteiner, May 11, 2019.

  1. Karnsteiner

    Karnsteiner

    Joined:
    Mar 24, 2013
    Posts:
    19
    Is there any faster way of filling up or removing items from a TransformAccessArray other than Add or RemoveAtSwapBack? With native arrays at least we can use unsafe/fixed to get a pointer to the beginning of the array and directly copy into them rather than using the index operator, but with TransformAccessArray I have not see any other way to get/remove elements other than these methods.

    My use case is that I am persisting a 10K TransformAccessArray and removing and adding items to it individually. This allowed me to persist fixed-size arrays for the transforms/related data for the same size, but be able to use less than that capacity with the related data being essentially sliced into the native arrays (I don't need to constantly resize array contents or iterate over them to set their contents to/from native arrays). Using the constructor for a newly allocated TransformAccessArray isn't an option as it doesn't allow you to set a start index, length for a passed array so that only a portion of it will fill that instance.

    Being able to add/remove ranges of a TransformAccessArray would dramatically speed up the worst case scenario of large numbers of items being added removed at once.
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    2,174
    So partitioning your transforms so you only have so many per parent, ideally root parents, will make a difference. So what I did was create a transform pool per partition and each partition has it's own IJobParallelForTransform. I order the partitions and when something needs one I try each one in order. I also have a grouping above that, so basically every feature has a partition group. Makes it more efficient for the whole ordered selection flow.
     
  3. Karnsteiner

    Karnsteiner

    Joined:
    Mar 24, 2013
    Posts:
    19
    I'm not sure that we're talking about the same thing; even if I partition the usage of TransformAccessArray and the related native/managed collections, I don't think that would mitigate the performance cost it takes to add or remove elements on a TransformAccessArray instance. Scene hierarchy for the transforms as far as parent, root isn't a factor in this as far as I know (at least for the work I'm doing). Has partitioning usage of a single TransformAccessArray collection into multiple had a significant impact for you?
     
  4. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    2,174
  5. Karnsteiner

    Karnsteiner

    Joined:
    Mar 24, 2013
    Posts:
    19
    I'm going to reiterate that my question is focused on finding the best way to add/remove transforms from a TransformAccessArray and not anything to do with partitioning the collection into smaller pools, scene hierarchy, or anything else unrelated for TransformAccessArrays where the elements never change.

    The goal is that I want to create a large fixed sized native collection for Transforms whose properties can be modified from a Job (TransformAccessArray seems to be the only one I've found that does this) but when it is not utilized in a job I want to as efficiently as possible add or remove items from it either as individual elements or a range of elements.

    My original question for reference:
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    2,174
    I understood. I was just offering a bigger picture solution that accounts for some things that maybe people don't always think of.

    If you are actually instantiating and destroying the gameobjects involved, that's a significant performance hit and dwarfs the cost of adding/removing to the array.

    If you are already pooling, then partitioning avoids having to add/remove, so that's a gain in performance there.

    I brought up hierarchy because you are moving transforms and in most context's that matters, and not everyone is aware of this.
     
  7. Karnsteiner

    Karnsteiner

    Joined:
    Mar 24, 2013
    Posts:
    19
    No worries, I appreciate the concerns/thoughts! Those are all good, valid points around transform usage, its just that they're adjacent to the real issue I'm tackling. Its frustrating because we have the ability to make jobs more dynamic in terms of adjusting the amount of managed data they would work on; we have the ability to slice in only the contents we want to have operated on to native arrays so that we do not need to constantly be passing an entire arrays of data and adjusting their size to fit the data we want to have operated on.

    The only exception to this is TransformAccessArray which I have only found documentation/examples for passing in an entire array of Transforms or adding/removing an element at a time. I was kind of hoping there is some unsafe way or doing this that I wouldn't be exposing directly to users, but would be able to take advantage of internally to circumvent this performance cost.

    There are implementation approaches that mitigate in some ways the performance cost of doing this (amortizing removes over several frames would help a great deal), but I would rather find performant ways of implementing simpler default behavior, even if they involve unsafe methods, before trying to move onto more complex mitigation strategies.