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

I've used unity almost every day for the last 2 years. Here are my thoughts.

Discussion in 'General Discussion' started by Pyromuffin, Mar 18, 2014.

  1. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    I'm just going to list some of my thoughts about Unity here.

    Unity is an amazing tool, without it, there's no way I could be a one man game dev team. Everywhere I go, I sing praises of unity to anyone who will listen. There's tons of resources available online for simple things, but more advanced topics have very little information about them, this is why most of my learning now comes from other people's packages. In the past, I've struggled to find information about compute shaders, DX11 features, physics engine scripting, path finding, custom deferred rendering stages, multiple render targets, stencil buffers, custom yieldinstructions, singletons/managers.

    at one point, I was very close to purchasing unity's premium support because I couldn't figure out whether the bugs I had were with my code, or in the engine. I was working on compute shaders and DX11 functionality and things weren't working, and I had no idea if I was doing things correctly because the documentation is poor on this topic, and it seems like there are almost no examples of how to do them correctly, and almost no one is posting on the forums or replying to posts concerning these topics. I ultimately did not purchase premium support because it was too expensive, and I only thought I would need to use it very briefly. If a cheaper option were available for less hours of support, I would have purchased that. As an indie developer working off of savings, my budget for this is very limited.

    I've found that it's mostly impractical to use Boo, even though it seems like a great idea, there's no support for it. Before I was a game developer, I was a python coder, so I miss python like syntax, but now I've grown used to C#. The fact that the different assembly types don't always work together compounds this.

    the first time I considered stopping using unity was when I found out I couldn't step the physics engine manually, which is somewhat required for certain multiplayer architectures. At that point, I spent a week integrating Bullet Physics with unity, which I ultimately did not end up using. I've since switched to a different architecture that doesn't require this.

    The engine not being threadsafe, or not having a multithreading model makes me worry about running into scaling problems down the line.

    I sometimes think that I could solve a lot of my problems (like seeing how some rendering things actually work under the hood or editing the physics engine) if I had the source code, but I have heard that this is almost impossible and also very expensive to license.
     
  2. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Ya the multi-threading issue is fairly big. And I think it's getting bigger as time goes on. However, I agree that Unity is probably the best game engine for any devs working on a project alone (i.e. a one man band).

    I don't think there's any way at all I could be as far as I am in my game development if I was using UDK or Cryengine. Perhaps the most important thing with regards to all other engines I've ever looked at, is that Unity's community actually tries to help you, and information is readily available. That is a huge plus.

    The only thing I've found Unity lacking in is out-of-the-box performance. You have to work pretty hard to get Unity to run things "well", depending on your game genre and scope of your game.
     
  3. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Why? What are you going to do that'll be limited by the lack of a threadsafe engine?
     
  4. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    I'm making a game that has a lot of agents doing lots of things at once. And as they get more complex, this is only going to become more of a problem. Though, Unity 5 seems to mention some kind of 'job queue' which might be what I'm looking for.
     
  5. Zeblote

    Zeblote

    Joined:
    Feb 8, 2013
    Posts:
    1,102
    I'm pretty sure this is only for the editor, as in the feature preview video it is mentioned under the headline "Editor"
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Do they directly interact with the Unity API? You can do lots of effective threading without needing to touch the Unity API, and AI is a pretty good example of that.

    --Eric
     
  7. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    I've had five-thousand odd agents bounding around (balls, physics simulation) without having to worry about the engine being thread-safe. If you're getting to the stage where you're overloading the engine then you're probably giving it so much input you'll overload the end user.
     
  8. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    You're right about AI being a good example for multithreading if I can isolate their behaviors from the unity API and I might look into that when or if it becomes relevant.

    job queues being only for the editor seems weird because they were showing it in the profiler.
     
  9. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    You don't "need" a threadsafe API, just like you don't "need" to code in C# because you could write a CLI DLL by tapping in the ones and zeros of the compiled binary using a telegraph. But a threadsafe API would certainly make multithreaded code much cleaner and easier.
     
  10. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Not necessarily. Making stuff thread-safe isn't magic, especially if you want to minimise performance issues, and it doesn't guarantee that your code will work as you intended. It can sometimes be easier to simply use non-thread safe code in a safe threaded manner than it is use thread-safe code in a safe manner (especially if you're lulled into think it's 'safe').

    Just as a simple example, what does the following print?

    Code (csharp):
    1.  
    2. transform.position = Vector3.zero;
    3. transform.Translate(1,0,0);
    4. print(transform.position);
    5.  
     
  11. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    It would print whatever the position was at the time it hit that line, if it was set in a different thread, which is what I expect. Devs are going to have to learn how multithreading works; it's not an optional thing anymore. Multi-core CPUs are the way of the future, and so is asynchronous programming. Trying to block it in an API because you're worried that noobs will make mistakes isn't going to be doable for much longer. Hopefully Unity will eventually keep up with .NET as well, which has been introducing a lot of new features to make parallel programming easier.
     
  12. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    If they wanted to do something extra to help devs with thread safety, they could add an "allowAsync" field in MonoBehaviour or GameObject that would be disabled by default, which would make that script only accessible by the main thread as it is now. You could also keep the current Start, Update, etc as synchronous and handled on the main thread, but introduce new StartAsync, UpdateAsync methods that would launch on a separate thread. That way people used to the way things work now would be pretty insulated.
     
  13. goat

    goat

    Joined:
    Aug 24, 2009
    Posts:
    5,182
    Seems to me that mobile devices would be loath to allow games to multi-thread...
     
  14. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    They all already allow it, and most modern phones have quad-core CPU's.
     
  15. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Whoa... who's blocking it in a API? Multithreaded code runs just fine in Unity - the api isn't blocking anything.

    Which is useful how exactly? I like to be able to easily reason what my code is doing, not simply say 'well, it'll do something... hopefully'.

    Wouldn't it be much easier to wrap it in a lock, or, if possible contention is an issue, wrap it in a task that will be executed at an appropriate time?

    Code (csharp):
    1.  
    2. lock (uniqueObjectLock)
    3. {
    4.     transform.position = Vector3.zero;
    5.     transform.Translate(1,0,0);
    6.     print(transform.position);
    7. }
    8. DoSafely( () =>
    9.     transform.position = Vector3.zero;
    10.     transform.Translate(1,0,0);
    11.     print(transform.position);
    12. });
    13.  
    Notice how suddenly we know exactly what is going on, it's easy to reason about, it's fast, we still have all the power of multithreading... oh and it *does not* require a thread-safe API.

    Yes, unity could do a few things to make multithreaded code a little bit nicer... but no, making the API thread-safe isn't necessary.

    I better get my multithreaded games apps off the market then...

    You do know you can do that... right now? The basic version could be written in, I don't know, 20 mins?
     
    Last edited: Mar 19, 2014
  16. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Yes it does. The API blocks itself from being accessed from separate threads. You are blocked from accessing almost anything Unity-related from other threads. Try it yourself and see, you will get a "___ can only be accessed from the main thread" for pretty much everything.


    Of course, but you didn't ask me how to make it better, you asked me what it printed.

    Yes it does. Try running that code in a separate thread, and you get this error: "InternalGetTransform can only be called from the main thread."

    No you can't, and I'm thinking you've never actually tried to run on a separate thread before. FYI, Unity Coroutines are not separate threads.
     
    Last edited: Mar 19, 2014
  17. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Which does not block multithreading :)

    Well, you're the one proposing a thread-safe API as a significant barrier. Did you not say the lack of a thread-safe API is akin to programming by binary via telegraph? How would you design a thread-safe API?

    So? We remove that warning... does that make the engine threadsafe?

    Hint: I can access a Dictionary<TKey, TValue> by multiple threads without any exception, does this make it threadsafe?

    Really? Coroutines are not threads? What a surprise! Maybe I'd known that if I'd manually reimplemented coroutines before...

    Oh wait I *have*, so maybe I *have dealt with threading before? Heck, here's an example from two plus years ago! I'm programming multi-threaded WPF code as we speak, as well as building highly scalable servers using async and tasks that interface with a thread running inside of Unity3d! And yes, It's entirely possible to build what you described.
     
  18. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    are you suggesting that these warnings do not matter? I have to admit, I haven't done much with unity multiprogramming because I have heard such bad things about it, but if it just spits out warning that don't matter then that seems pretty cool.
     
  19. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    No the warnings matter (at least, as far as I'm aware), but they are easy to work with.
     
    Last edited: Mar 19, 2014
  20. RElam

    RElam

    Joined:
    Nov 16, 2009
    Posts:
    375
    In the context of this discussion, that's entirely untrue. What engines have their game logic/scripts generically threaded, or threaded at all? If .1% of games do it, at best, how would that not be optional? I'd be interested to know the names of the games you know to have this type of multithreading.

    I've got decent experience with multithreading, and this idea of a threadsafe API sounds magical, but in practice it's far more complex than you seem to think. The example given by npsf3000 is rather excellent, and here's the part of it that's really bad: Threading issues such as that one will not cause you a problem the vast majority of the time. That'll likely pop in a bad way 1 in 1M iterations, so now you have a super intermittent bug, which will suck development time, development time that could have been spent on anything (including optimization). Multi-threading, even for the best devs, is a bug spawner, plain and simple. For some systems, it's well worth it, but any change that boils down to 'let's sacrifice developer time for an optimization' better really, really need it.

    So, the end question is not an argument of is multithreading good, sure, multithreading is good, but it's also already being done alot (rendering, physics, audio, animation, all threaded/threadable services without impacting end users). The question is what are your cores doing when the scripts are running, ie, do you have idle cores waiting for scripting to complete, and can they be doing nothing else but running scripts? That's kinda hard to answer right now, Unity needs a telemetry style profiler to answer that, like the thread profiler shown here.

    But this idea that it's a truly game blocking thing... no, not buying it, not by a long shot.
     
  21. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I don't mean to be rude, but honestly I'm not sure what you're talking about. I know you can start a thread and do non-Unity stuff but clearly that is not what the original poster nor I was talking about. I mean the API itself (like any interaction with Unity components) is blocked from access on other threads.

    It's not a warning, it's an exception that gets thrown when you access Unity from a separate thread, and it literally blocks the call. Your example does not actually work. Seriously, just type it in and try it. The object will not move; it will throw an exception as soon as you try to access the transform.

    It really isn't. You can't access the base MonoBehaviour properties from a different thread.
     
    Last edited: Mar 19, 2014
  22. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Sorry, I was responding to this statement you made:

    You don't "need" a threadsafe API, just like you don't "need" to code in C# because you could write a CLI DLL by tapping in the ones and zeros of the compiled binary using a telegraph. But a threadsafe API would certainly make multithreaded code much cleaner and easier.

    Which, given that I've written plenty of multithreaded code in Unity either makes me a genius of chuck norris proportions or your statements to be grossly exaggerated and not at all reflective of reality.

    And? Can you please explain to me, someone who writes and uses multi-threaded code both in and outside of unity3d and has dealt with this error and it's analogs repeatedly, why this is some sort of major problem? Is this as far as you've gone?

    Or should I restate my question: Let's remove this exception - do you think makes unity3d threadsafe?

    Which in no way invalidates what I said. How about you spend 20 mins and nock up a version, and show me where you think the problems are?
     
    Last edited: Mar 19, 2014
  23. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    My point was that just because you don't "need" something doesn't mean it's not good to have. You don't need 3D, or sound, or more than two colors on the screen to make a game, but you can certainly make better games with those things. Similarly, having a multithreaded API would help to make better games, especially has CPU cores continue to increase and parallel programming becomes more popular.

    The problem is you can't actually do anything Unity related in an async call. You can't move a character, or instantiate a new game object, or play a sound, or anything like that. A Start() method where you can't access anything Unity-related is not very useful.
     
  24. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    So now you want a multithreaded API? Could you elaborate how that would appear?

    Ahh so this is the problem! We can't instantiate game objects or play sounds fast enough!!! Can you present me a use-case where this is an actual problem?

    1) Says who?
    2) If you want to write a start method that can access Unity API's why don't you simply write that?

    ------

    TD;LR: I write and use multithreaded code. I can't see any immediate issues with Unity's API that need addressing - sure there are 'nice to haves' just like it'd be 'nice to have' that GUI, or a modern version of mono.
     
  25. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    You need a use case for why a slow game engine is bad? I would think it would be obvious... games are always pushing the envelope trying to have better graphics, more effects, etc, on PC, mobile, and consoles. The slower your game engine is, the less you can do with it. Are you seriously saying that bad performance doesn't matter?

    Common sense. Go into your Unity project and change all your Start and Update methods so that they no longer access anything Unity related. You wouldn't really have a Unity project anymore.

    You CAN'T. I don't know why you can't grasp that. You LITERALLY CAN NOT access the API from a different thread. How are you not getting that?


    I believe you, but I don't think you've ever written multithreaded code IN UNITY. Seriously, try even the most trivial example and you will see that I'm not lying about the main thread exception. Try your own example; it does not run.
     
  26. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Whoa, who said that that we wanted a slow engine? Maybe the guy who's asking for a whole bunch of work adding in thread safety without any thought to the performance implications?

    Ahh I understand, when you said:

    You could also keep the current Start, Update, etc as synchronous and handled on the main thread, but introduce new StartAsync, UpdateAsync methods that would launch on a separate thread. That way people used to the way things work now would be pretty insulated.

    And:

    A Start() method where you can't access anything Unity-related is not very useful.

    You actually meant to say:

    Go into your Unity project and change all your Start and Update methods so that they no longer access anything Unity related.

    You see, I consider those statements to be very different.

    Because *I* have posted demo's showing thousands of objects being moved around by a physics engine, in Unity, that does not use the main Unity thread for its computation. So obviously I don't have a problem with this error... if you actualy meant to state:

    I CAN'T. I don't know why you can't grasp that. I LITERALLY CAN NOT access the API from a different thread. How are you not getting that?

    Then I might be able to assist you :)

    I have around a dozen apps, IIRC, that run on my multithreaded code. I have already linked to not one but *two* web players running multithreaded code. How can you possibly tell me that multithreaded code does not work?
     
    Last edited: Mar 19, 2014
  27. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    imo npsf3000 is being rather cagey about what magic he's working to get unity api access from other threads. Reflection wizardry? Arguing about whether or not npsf3000 can write multithreaded code is not productive. Telling people you can write multithreaded code that accesses the unity API in a mysterious and not helpful way is also not productive. I can imagine a scheme where you roll all your own unity-esque analogs and then push them out to worker threads, and when your worker thread dispatch is done, you compile all the results in the main thread, translating between your homegrown types and the unity api. This technique seems really cumbersome, but it seems possible.
     
  28. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Yeah, I agree that NPSF3000 guy is a tool! He should show people how he multithreads, not be all mysterious! For example, this is what he should post:

    Not really. Take my simple physics demo's engine for example - all it really needs to know about a transform is the following:

    1) Position.
    2) Rotation.
    3) Scale.

    In the earlier example, it only ever needed to read once, and would simply write back every fixed update. In return for that little bit of wrapping, you got multithreading, lots of awesome hooks into the engine, and collider types that simple don't exist in Unity.

    If you're making something a little more generic, there are some pretty cool wrapping idea's one could implement to make the process much nicer (I especially like the idea of making coroutines threadable!)
     
    Last edited: Mar 20, 2014
  29. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    FFS, I can only imagine you're trolling at this point. As I said about five billion times, your example DOES NOT WORK. If you want to keep pretending it does, then go ahead, but anyone in the thread can just copy and paste that into a script on their own and see for themselves that it doesn't work. Either you're purposefully lying to troll us, or you've never actually tried running on a separate thread and aren't sure how but are trying to save face. Either way, I'm going to have to just walk away at this point.
     
    Last edited: Mar 19, 2014
  30. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    amen brother ^^
     
  31. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    additionally, i would put this to you nps. try manipulating vertices and such for multiple meshes as in CDLOD, in unity or any LOD algorithm for that matter... tell me what you find..

    the 'can only create in main thread' issue, hobbles any real ability to sqeeze out some performance..

    in my experience, any time you have a critical section, it's a bottle neck, which then removes the point of multi threading. true multi threading should be a fire and forget type thing where each thread is completely self contained.. no thread racing etc etc etc..

    hacking around it with the use of anon delegates still won't work.. you cannot create from a different thread..

    coroutines are NOT threads.. they are time slices.. that is why you can create on the main thread..

    for the record.. ANY engine can allow multithreading.. hell, i could even do it in XNA.. when you create the dx device, you can even stipulate whether or not it'll be multi threaded..

    there are some things that you can get away with.. for example, you can access vectors and other types, but not active objects that require a reference/context.. those are attribute flagged as main only..
     
  32. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Sure thing, would you like to provide an example as I've not dealt with CDLOD before?

    If each thread is complete self contained, how would you share information? Even more strict models, e.g. erlang (where everything is immutable) uses message passing to share information.
     
  33. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    um, seriously? you pass it in.. i personally don't use threads to work on static or global data.. that's a no-no, because it requires a critical section, thus making the whole point of threading kind of moot.. as far as that goes, and mebbe i'm just a purist, but i NEVER have global or static classes, types or variables. it's a sure sign of bad architecture...

    i look at it this way: just because you CAN thread something, doesn't necessarily mean you SHOULD thread something.. i'm not telling you how to thread, but if you control thread flow/racing via critical sections, something is wrong.. imo, the data being worked should be able to live independently from data being worked by other threads.. do people thread other ways? of course, is it right? shrug.. these are just the rules i try to follow..

    google CDLOD or filip Strugar. try porting his technique to UT. you'll soon see that what works well, not only in his sample, but in XNA/C# ports, that they have no problem with the ability to work. it's all of the self imposed crap in UT that becomes the issue.. first and foremost, not being able to create or modify gameobjects on separate threads, now i have to wrap those objects and try to synch them via some sort of queue system, that i then have to create and assign all of the verts to the meshes etc.. which causes huge stuttering.. it's either that, or i have to coroutine that, and then the lag is unbearable..

    i was investigating a way to be able to keep a modicum of tessellation on the cpu so that i could update collision meshes. i'm still investigating using compute shaders to tessellate, then use getdata to update the collision mesh, but then i have to sort out using meshes as basically a buffering system..
     
    Last edited: Mar 20, 2014
  34. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Have you tried reinstalling the Unity plugin? What error are you getting? Works fine over here:


    $Screenshot 2014-03-21 14.34.33.png

    Then surely you must be using either global/static methods, or the data you pass in itself to communicate?

    Which doesn't seem to be an issue of the API's thread-safeness or lack thereof?

    I've not got that much free time ATM :(
     
    Last edited: Mar 21, 2014
  35. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    "Then surely you must be using either global/static methods, or the data you pass in itself to communicate?"

    i just stated i DON'T use globals. i pass whatever data that needs to be worked INTO the thread that needs to work it. the main point of contention here is that i'd like to be able to create and modify gameobjects FROM separate threads, which means: it wouldn't be bottlenecked into 1 thread. thus eliminating stuttering or lagging..

    "Which doesn't seem to be an issue of the API's thread-safeness or lack thereof?"

    the whole reason i have to do it that way, is BECAUSE of the "API's thread-safeness or lack thereof". of course it's an issue. in any case, i can ONLY create and/or modify a gameobject from the main thread ONLY, this is a bottleneck.

    if you find some time, i would highly suggest you check out Filip's tech. it might just be a viable way to update collision meshes while obtaining tessellation, and sqeezing further performance out of UT.
     
  36. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    How do you know that this limitation of the API is a bottleneck causing stuttering and/or lagging?
     
  37. Mistale

    Mistale

    Joined:
    Apr 18, 2012
    Posts:
    173
    npsf3000: I can only assume that you're misunderstanding what Marionette and Makeshiftwings are saying...
    Wrapping API calls from worker threads to be run on the main thread is NOT a viable solution to the lack of thread-safety of the API.

    One example is compressing or decompressing textures that have been read from disk or via WWW.
    By using coroutines instead of threads, in one of the time-slices the comp/decomp is performed (in the main thread), and it causes stutter.
    By using workerthreads, at some point in time, comp/decomp is performed via wrapping or similar methods, in the main thread, and it causes stutter.

    In some causes the above mentioned workarounds are valid, but that's only when the code to be run can be broken down into multiple slices that each has little or no impact on fps, even if run on the main thread. If you happen to use one or more API calls that needs a certain amount of time complete, then we CAN'T workaround the stuttering as of now.

    The only REAL solution is to allow calls to Unity's API to be performed in any thread, which would NOT cause stutter when run on multithreaded devices.
     
  38. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Why not? I've written plenty of multithreaded code that works *just* fine using this paradigm.

    So the problem here, if I'm reading you correctly, is the fact that texture compression/decompression is done on the main thread? If so, one solution might be to ensure that compression is done on worker threads (either behind the scenes, or in our own code), which interestingly enough, does not require that the Unity API be thread safe.
     
    Last edited: Mar 24, 2014
  39. Mistale

    Mistale

    Joined:
    Apr 18, 2012
    Posts:
    173
    npsf3000: It was just one example, don't read too much into exactly what needs to be done on the main thread. Just assume that I need to execute an API call, and that the call itelf blocks the main thread for a period of time.

    In this particular case, It's about Texture2D.LoadImage() blocking the main thread for a long time on mobile devices.
    It doesn't matter if I read the image-data in a coroutine or a separate thread, the main thread will still be blocked when I do the actual conversion from byte [] to Texture2D.
     
  40. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Oh I understand that. Also understand that the solution here is get the API call not to block the main thread, not randomly ask for 'thread safety' which may or may not solve the problem, is complex to implement and may have performance issues of its own.
     
  41. Mistale

    Mistale

    Joined:
    Apr 18, 2012
    Posts:
    173
    @npsf3000: Agreed, any solution that eliminates stuttering would be fine by me. Doesn't matter if Unity makes time-intensive calls yieldable or if they make the whole API thread safe.
     
  42. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    the difference is that if the API was threadsafe, it would kill multiple birds with one stone. one glaring reason for the threadsafe-ness is because of the way their scene graph is architected. the fact that i have to statically create a container (mesh) in the scene before i'm even able to assign verts to it, makes it much more complicated to get around. this means, i have to either, precreate all of the meshes i think i'll need first, *then* thread the vert creation/modification/LOD etc but this only addresses initial creation, not modifications, or stack my threads to wait until the creation is done on the main thread (same with modifications) which causes stuttering or coroutine everything which means as i calculate LOD based on camera distance, the updated LOD 'lags' behind by up to several seconds depending on LOD level.

    none of the above scenarios are acceptable.

    the only thing i can think of that might work (and i haven't tried this of course) would be to use compute shaders to do the actual LOD/tessellation, THEN use getdata() and apply to the mesh/collision mesh. i have no idea if this would work, or if it would be performant. but it's all i can think of for now. UT5 will supposedly have job queues, but so far, i haven't seen anything detailed or descriptive about it.
     
  43. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    At some point, game engines will completely separate rendering logic from game state mutation. The rendering engine will take a game state as an input and do it's own thing in a separate context. As linearly sequenced CPU time becomes more and more scare relative to total CPU availability, GPU, and memory, there is no question of where things are headed if you care about maximizing resource utilization.

    Of course, Unity (and as far as I know, the other leading engines) are in no position to get to a clean separation of concerns like this any time soon for myriad reasons.
     
    Last edited: Mar 27, 2014
  44. Marionette

    Marionette

    Joined:
    Feb 3, 2013
    Posts:
    349
    agreed, and AMD's mantle is an example of that. however, even in basic DX tutorials you have had the ability to mutilthread to a multithreaded device. what i hate are self imposed limitations presumably due to questionable architecture.
     
  45. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Not necessarily. Thread-safeness doesn't mean all that much, and isn't free. All thread-safeness means is that you can access the API from multiple threads safely. It doesn't mean that the API is doing any work on multiple threads, or even any thread other than the main thread.

    Since people are getting confused, I thought I'd whip-up a small example:

    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Diagnostics;
    5. using System.Linq;
    6. using System.Text;
    7. using System.Threading;
    8. using System.Threading.Tasks;
    9.  
    10.  
    11. namespace ConsoleApplication21
    12. {
    13.     class Program
    14.     {
    15.         static int mainThreadID;
    16.         static volatile bool multiThreaded = true;
    17.  
    18.  
    19.         static void Main(string[] args)
    20.         {
    21.             mainThreadID = Thread.CurrentThread.ManagedThreadId;
    22.             Console.WriteLine("Main thread ID is {0}\n", mainThreadID);
    23.  
    24.  
    25.             //Let's start by using the default implementation, work can only be called on the main thread!
    26.  
    27.  
    28.  
    29.  
    30.             Console.WriteLine("Creating and compressing 10 textures");
    31.             var sw = Stopwatch.StartNew();
    32.             for (int i = 0; i < 10; i++)
    33.                 new Texture().Compress();
    34.             Console.WriteLine("Finished and compressing 10 textures in {0}ms", sw.ElapsedMilliseconds);
    35.  
    36.  
    37.             Thread.Sleep(100);
    38.             Console.WriteLine();
    39.             Console.WriteLine();
    40.  
    41.  
    42.             //Well, that's not very good!  How about we make this threadsafe?
    43.             //First we need to start running in other threads, and give the main thread soemthign else to do.
    44.             new Thread(MultiThreadedMain).Start();
    45.  
    46.  
    47.             MainThreadDoSomethingElse();
    48.  
    49.  
    50.             //back in the main thread, now let's try a fixed version;
    51.  
    52.  
    53.             Console.WriteLine("Creating and compressing 10 textures");
    54.  
    55.  
    56.             sw = Stopwatch.StartNew();
    57.             var tasks = Enumerable.Range(0, 10)
    58.                 .Select( i => new PossibleFixedTexture().CompressAsync())
    59.                 .ToArray();
    60.             Task.WaitAll(tasks);
    61.             Console.WriteLine("Finished and compressing 10 textures in {0}ms", sw.ElapsedMilliseconds);
    62.  
    63.  
    64.             Thread.Sleep(100);
    65.             Console.WriteLine();
    66.             Console.WriteLine();
    67.  
    68.  
    69.             Console.WriteLine("Press any key to Exit");
    70.             Console.Read();
    71.         }
    72.  
    73.  
    74.         static void MultiThreadedMain()
    75.         {
    76.             Console.WriteLine("Creating and compressing 10 textures");
    77.             var sw = Stopwatch.StartNew();
    78.             var texture = new ThreadSafeTexture();
    79.             Parallel.For(0, 10, i => texture.Compress());
    80.             Console.WriteLine("Finished and compressing 10 textures in {0}ms", sw.ElapsedMilliseconds);
    81.  
    82.  
    83.             Thread.Sleep(100);
    84.             Console.WriteLine();
    85.             Console.WriteLine();
    86.  
    87.  
    88.             //That was interesting,  this is very threadsafe...
    89.             //but still runs everything in the main thread and
    90.             //isn't ver fast.
    91.  
    92.  
    93.             //lets' go back to the main thread now:
    94.             multiThreaded = false;
    95.         }
    96.  
    97.  
    98.         static void MainThreadDoSomethingElse()
    99.         {
    100.             while (multiThreaded)
    101.             {
    102.                 Thread.Sleep(1);
    103.                 Action workUnit = null;
    104.                 lock (ThreadSafeTexture._lock)
    105.                     if (ThreadSafeTexture.toDo.Count > 0)
    106.                         workUnit = ThreadSafeTexture.toDo.Dequeue();
    107.                 if (workUnit != null) workUnit();
    108.             }
    109.         }
    110.  
    111.  
    112.         public class Texture : ITexture
    113.         {
    114.             public void Compress()
    115.             {
    116.                 if (Thread.CurrentThread.ManagedThreadId != mainThreadID)
    117.                     throw new InvalidOperationException("This needs to be called from the main thread");
    118.                 DoWork();
    119.             }
    120.  
    121.  
    122.             private void DoWork()
    123.             {
    124.                 Console.WriteLine("Starting work on thread: " + Thread.CurrentThread.ManagedThreadId);
    125.                 Thread.Sleep(1000);
    126.                 Console.WriteLine("Finishing work on thread: " + Thread.CurrentThread.ManagedThreadId);
    127.             }
    128.         }
    129.  
    130.  
    131.         public class ThreadSafeTexture : ITexture
    132.         {
    133.             //These would normally be invisible from the caller.
    134.             public static object _lock = new object();
    135.             public static Queue<Action> toDo = new Queue<Action>();
    136.  
    137.  
    138.             public void Compress()
    139.             {
    140.                 Console.WriteLine("Compress called on thread: " + Thread.CurrentThread.ManagedThreadId);
    141.                 bool complete = false;
    142.                 lock (_lock)
    143.                     toDo.Enqueue(() => { DoWork(); complete = true; });
    144.                 while (!complete) Thread.Sleep(1);
    145.                 Console.WriteLine("Compress finished on thread: " + Thread.CurrentThread.ManagedThreadId);
    146.             }
    147.  
    148.  
    149.             private void DoWork()
    150.             {
    151.                 Console.WriteLine("Starting work on thread: " + Thread.CurrentThread.ManagedThreadId);
    152.                 Thread.Sleep(1000);
    153.                 Console.WriteLine("Finishing work on thread: " + Thread.CurrentThread.ManagedThreadId);
    154.             }
    155.         }
    156.  
    157.  
    158.         public class PossibleFixedTexture : ITexture
    159.         {
    160.             public async void Compress()
    161.             {
    162.                 if (Thread.CurrentThread.ManagedThreadId != mainThreadID)
    163.                     throw new InvalidOperationException("This needs to be called from the main thread");
    164.                 Console.WriteLine("Compress called on thread: " + Thread.CurrentThread.ManagedThreadId);
    165.                 await Task.Run(new Action(() => DoWork()));
    166.             }
    167.  
    168.  
    169.             public Task CompressAsync()
    170.             {
    171.                 if (Thread.CurrentThread.ManagedThreadId != mainThreadID)
    172.                     throw new InvalidOperationException("This needs to be called from the main thread");
    173.                 Console.WriteLine("Compress called on thread: " + Thread.CurrentThread.ManagedThreadId);
    174.                 return Task.Run(new Action(() => DoWork()));
    175.             }
    176.  
    177.  
    178.             private void DoWork()
    179.             {
    180.                 Console.WriteLine("Starting work on thread: " + Thread.CurrentThread.ManagedThreadId);
    181.                 Thread.Sleep(1000);
    182.                 Console.WriteLine("Finishing work on thread: " + Thread.CurrentThread.ManagedThreadId);
    183.             }
    184.         }
    185.  
    186.  
    187.         interface ITexture
    188.         {
    189.             void Compress();
    190.         }
    191.     }
    192. }
    Here we have the standard non thread-safe version, a very thread-safe version, and a version that actually tries to solve the problem through async and tasks... but isn't thread-safe.
     
  46. charmandermon

    charmandermon

    Joined:
    Dec 4, 2011
    Posts:
    352
    @NTSF300 I agree!