Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Huge performance issue due to vSync (option that can't be disabled)

Discussion in 'Web' started by jtiret, May 14, 2021.

  1. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hello there,

    I have built my application to WebGL locally and connected it to Unity's profiler.

    When I am in fullscreen (4K external screen), I have huge performance issues, the framerate is very low.

    Here is what I see in the profiler:

    Screenshot_2021-05-14_at_11_17_19.png

    I tried to disable vSync (through code and via Quality settings in the menu) but I keep having the same issue (observing the same behaviour shown by the profiler).

    When I show a Debug.Log of the vSync count settings, it displays a value of zero (disabled), which seems to be ignored.

    I'm using a Mac with Google Chrome, Unity 2020.3.7f1.

    Could someone help me in solving this performance issue?

    Thanks in advance,
    Jonathan
     
    Whatever560 likes this.
  2. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Unfortunately web browsers do not enable rendering with vsync disabled. Browser compositing is always performed with vsync on. It would be possible to decouple rendering from vsync, but unlike in native 3D rendering, in browsers that would only cause dropped frames and stuttering.

    I would assume here that the performance difference here is instead due to the increased number of pixels rendered on screen in fullscreen mode, compared to windowed mode. If you go in fullscreen mode on a display that has a smaller resolution than 4K, does that give a lesser impact on the issue?
     
    FOAG and De-Panther like this.
  3. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hi @jukka_j and thanks for your quick answser.
    I initially answered right after your post the other day but I deleted my answser as I wanted to investigate a little more.

    I think you are right and that vSync is not the issue. It's working much better on smaller resolution or when I reduce the size of the screen.

    Do you have any clue on how to deal with it? (because some users will have large screen or just Retina screen and I can't control that, I want them to be able to play the game)
    I tried reducing the window.devicePixelRatio value (in JS) or decrease
    config.devicePixelRatio (initially to 2, settings it to 1), which improves performance but the UI (using UI Toolkit) is just ugly in this case.

    I also tried reducing the render scale of the Universal Render Pipeline settings because it doesn't affect the UI, but it doesn't improve performance that much.

    Do you know how to improve performance and having a lisible UI?

    Thanks in advance for your help
     
  4. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    First thing to double check is that the project is targeting WebGL 2 in the graphics settings. WebGL 1 will give bad performance due to the number of emulation aspects that URP shaders need to do there.

    The next thing I would do is, since it is observed that the issue is dependent on rendered pixels, so a GPU fillrate/shader execution throughput issue, is to debug whether there might be some specific object or objects in the scene that are slow to render. Maybe there is one object with a large amount of geometry that is causing a large performance impact? Or maybe there is some specific shader that is causing slowness to render? Try to see if hiding objects uncovers a clue as to what is the cause of the slowdown.

    If all objects seem like equally slow to render, try investigating if it is possible to reduce the number of objects to render, e.g. via batching. Unfortunately instancing is out of action from URP in WebGL builds, since that historically required OpenGL ES 3.1, but we have been working on getting it enabled also on OpenGL ES 3.0 level of hardware - i.e. on WebGL 2.

    Even though the issue does suggest to be on the GPU performance side, it can also be useful to do a profile of the CPU side, using browser's performance profiles. Maybe there are some hotspots there still that could help e.g. optimize some script execution, or similar.

    If the project is public and you have a link, I can also give it a quick profile to see how it looks like on my system.
     
    FOAG likes this.
  5. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hi @jukka_j

    First, thanks for your detailed answer and for proposing your help, that's very kind of you!

    Sure, the project is live at this URL: https://app.dev.dinogaia.com/ (you can show the frame rate by pressing SHIFT + F)
    (you don't need to login, you can see the performance issues right on the home screen)

    Regarding your suggestions:
    • Yes I confirm that the target is WebGL 2.0 (with Linear Color Space Rendering)
    • I will try investigate whether hiding objects uncover some objects that would be very slow to render, but it's hard to do so because I have to build to WebGL every time. You might wonder why I can't test that in the Editor? Well, the performance in the Editor and Standalone builds are much better than in WebGL. Which is surprising because the doc states that performances should be equivalent (comparing Standalone and WebGL).

      Moreover, I have seen that my WebGL build can also be slow on just simple loading screens (containing only UI based on UI Toolkit), so without any complex objects to render).
    • I didn't try batching for the reasons above, there seems to be a performance issue specific to WebGL. Moreover, my scene doesn't contain many objects (so not many batches) or animations so I concluded that this might not be the problem, below are the stats displayed in the Editor (for the home screen that you can see at the URL above):
    Screenshot 2021-05-22 at 10.57.39.png

    In order to illustrate that the performance are much better on Standalone than on WebGL, you can compare the WebGL version: https://app.dev.dinogaia.com/ with the Standalone Mac App (https://static.dev.dinogaia.com/apps/dinogaia-macos.zip) (but I don't know if you use Mac)

    These two apps are two different targets of the exact same codebase.
    To be honest, when displaying the Standalone Mac App full screen on a 4K screen, it's also slow, but nothing compared to WebGL.

    I will check the browser profiling (not used to browser profiling yet so will need to dig a bit). Do you see something particular on your side on https://app.dev.dinogaia.com/ ? (you can show the frame rate by pressing SHIFT + F)

    Thanks again your help and support!
     
    Last edited: May 22, 2021
  6. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Surprisingly, most of the overhead isn't due to Rendering but Scripting (see the screenshot attached).

    However, the script functions being called might be rendering-related or something. I don't have much experience in profiling WebGL applications so I might be wrong.

    Screenshot_2021-05-22_at_11_23_23.png

    By the way, you can see that the screenshot is quite large, this gives an idea of the number of pixels that should be rendered fullscreen.
     
  7. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks for the test case. Profiling that is a little bit tricky since that build is missing profiling frames for browser devtools.

    Could you do a new build that would have the Emscripten linker flag "--profiling-funcs" active? That can be achieved by setting the field

    Code (CSharp):
    1. PlayerSettings.WebGL.emscriptenArgs = "--profiling-funcs";
    in a C# Editor script before doing the build. You can use the attached script buildWebGL.cs for example to get a dropdown menu that can achieve that. (see the documentation of the script at the beginning of the file)

    That will give profilers more information about those wasm-function[...] blocks in the profile.
     

    Attached Files:

    FOAG, jtiret and gtk2k like this.
  8. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Thanks jukka_j!

    I'm actually using Unity Cloud Build to deploy this WebGL app so I've added the line within the PreExport method which was already set up in CloudBuild:

    Code (CSharp):
    1.     public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
    2.     {
    3.         PlayerSettings.WebGL.emscriptenArgs = "--profiling-funcs";
    4.     }
    It's currently being built. I will let you know once it's deployed. And will dig into your example script as well as there might be other useful build options to be aware of in it. :)
     
  9. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    @jukka_j so the deployment is completed with the new option. To be honest, I am not fully sure how to check whether this option has been taken into account into the build because I didn't try to dig into the function calls in the first place. Would you mind checking and tell me if you see a change? You may need to do a hard refresh.

    I guess that what I need to do is to select a frame and check the functions taking the most % of time in the Bottom / Up tab, is that a right assumption?

    Here is an example of what I can observe:
    Screenshot 2021-05-24 at 12.12.22.png

    But again, I am not sure if there are all the details provided thanks to the profiling-funcs option. Although I can see that there are symbolized functions that give some clues.

    What do you think?

    Thanks in advance for your support, I very much appreciate it.
     
  10. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks for the updated test case. I took it for a spin in Firefox, and recorded my impressions on a video. You can view it here: https://drive.google.com/file/d/1GIXkDwYyu73v64b9n4ORQJAJgDe3WuNV/view?usp=sharing

    The captured performance profile can be viewed here: https://share.firefox.dev/34fYqBS

    The following items came up:
    - loading Mecanim skeleton via .json seems to be slow. Does Mecanim support binary skeleton assets? If not, I would report that as a bug.
    - one of the slowdowns in JSON parsing is caused by a codegen issue in __atomic_fetch_add_8, that should be fixed in Unity 2021.2 Beta and newer, when that becomes available.
    - likewise, the performance penalty from populateUniformTable() should be optimized in Unity 2021.2 Beta and newer.
    - URP _Light2DLookupTexture_GetFalloffLookupTexture() function shows up hot in the profiles. If that shows up consistently on loading, definitely file a bug on that.
    - loading A8(?) textures incurs an unexpected performance slowdown that contributes to stuttering. If you are able to isolate this from a profile to a test case, certainly go ahead and report that as a performance bug.
    - using nonstandard FPS option in project settings is known to cause stuttering. Reverting to the default setting (I think it is value 0 by default) should improve animation smoothness

    If you can get and share a similar profile from the slow system, maybe that could be compared to the fast one above to see if the shape of the profile is somehow fundamentally different.
     
  11. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    @jukka_j First off, thanks a lot for taking the time to digging into all these details. I've learnt so much with your video. I can't tell how much I appreciate your help and support!

    Here is a profile I've made with Firefox: https://share.firefox.dev/3vmPjee

    It looks like unlike your profile, my frames take longer to render.

    Moreover, I noticed something that takes significant time on my computer that doesn't seem to take as much time on yours:

    Screenshot 2021-05-25 at 19.19.58.png

    This "wait-related" function reminds me of some cryptic things I observed on Unity profiler when running in Play mode:

    Screenshot_2021-05-25_at_19_25_38.png
    The performance is much better in the Editor but yet, it's stuttering. What I can see is that much of the time is taken by this "Gfx.WaitForPresentOnGfxThread". My understanding was that this meant that the CPU was waiting for the GPU, but I never found any clue to get rid of this. I concluded that this might be an incompatibility with my graphic card (my settings are below). I suspect that WaitForPresentOnGfxThread is related to what I see in the Web profiler (WebGL's clientWaitSync function). What do you think?

    By the way, at some point, I wanted to use Unity Profiler to profile GPU, but my graphic card isn't compatible with Unity Profiler unfortunately.

    Anyway, the game was stuttering a lot, much more than on your screen recording although I was not full screen. You can see how the WebGL app behaves on my computer:


    Regarding this slow FPS I was mentioning, I can tell that the performance is much better on a Standalone Mac Build than on WebGL (on the same machine of course). On my iPhone this 100% smooth, I don't even see any optimization needed on mobile.

    My settings :
    My graphic card is the following: Intel Iris Plus Graphics 1536 MB
    Processor: 2,3 GHz Quad-Core Intel Core i7
    My laptop is connected to a high-definition external screen.

    To answer a few of your highlights/questions:
    • The skeleton mecanim related functions actually come from Spine Unity plugin. All the JSON animation files are formatted in Spine format and loaded at runtime. I will check whether I can have them loaded as binary to avoid all the overhead due to JSON decoding. This can have a huge impact on loading indeed, it's a very good catch.

    • Ok, I completely understand why setTimeout can make the application stuttering. For the record, I initially changed the targeted frame rate because I noticed that Unity can go at high levels of frame rate (100, 150, 200, …) which I considered not necessary and resource-wasting. I wanted to set frame rate to something reasonable around 60. Is that the right thing to do for other platforms (not for WebGL)? I didn't think it would make any difference on WebGL as I thought that frame rate would be conditioned by vSync. o_O
      Alright then, I will reset the targeted frame rate to the default value, at least for WebGL.

    • I will check the other highlights you've made regarding _Light2DLookupTexture_GetFalloffLookupTexture and A8 textures.

    • Regarding layout updates (that you've mentioned in your video), I'm a bit surprised as the app doesn't do any update each frame. Maybe UI Toolkit does a refresh each frame though. I will have a deeper look on it as well.

    Again, thanks a lot for your help!
     
    Last edited: May 25, 2021
  12. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    That is a very interesting profile! It looks like glClientWaitSync() is indeed behaving very badly on that GPU. Is the computer some flavor of macOS? If so, can you specify the exact model? I wonder if our QA might have that exact same machine in their test bench.

    One additional thing I'd love to see is whether Chrome has identical performance issue on that system compared to Firefox? That is, I wonder if glClientWaitSync() is just a Firefox issue here, or if Chrome has same general bad stuttering performance on this project? (I presume yes, since https://forum.unity.com/threads/hug...o-vsync-option-that-cant-be-disabled.1109624/ mentioned that you were testing on Chrome, but want to double check)

    Does using an external display vs not using one affect the issue? If you just use the main display without an external display connected, does that avoid the long glClientWaitSync() issue in Firefox profile?

    I think this occurs on other platforms if vsync was disabled. The best option for performance and conserving resources should be to enable vsync on all platforms, and keep the default setting to target the native display frame rate.
     
    FOAG likes this.
  13. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Here is my exact Mac model (which I "customized" when ordering to Apple in order to have better settings, this is not the default config):
    Screenshot_2021-05-26_at_08_16_32.png
    Storage:
    Screenshot 2021-05-26 at 08.18.53.png
    Display settings:
    Screenshot 2021-05-26 at 08.19.29.png
    I bought this computer last year (this is the last generation of Mac with "good" settings, I didn't expect any performance issue).

    Yes I usually use Chrome and I confirm that the behaviour is overall the same. I am not very familiar with its profiler so I am not sure if I can have a similar flame graph with as much details but overall the performance is the same. Here is the profile I exported from Chrome: https://drive.google.com/file/d/1JRw5ZW2mqHv4dP1xH9gLIdj3TMalEvIB/view?usp=sharing

    Running on my laptop's screen
    Here is a profile of how it behaves on my laptop screen: https://share.firefox.dev/3oRo5tY
    This is much better, we don't see as long clientWaitSync calls. But it's stuttering a little (even with FrameRequestCallback instead of setTimeout, I have switched back to the default target frame rate setting).

    I think it's stuttering because, for some frames, WaitForPresentOnGfxThread takes a lot longer. I noticed this in the Editor profiler. The game can be smooth overall, but some frames take longer because of WaitForPresentOnGfxThread taking a lot of time, at regular interval (spikes appear in the Unity Profiler, as shown on the screenshot in my previous post).

    So even if it's better on my laptop screen, I would expect better performance given that the "relative simplicity" of the scene being rendered. One last thing: even if it's running better on my laptop's screen, my computer can be very noisy (I guess that it might be enabling the so-called Turbo Boost or something when running the game).

    How does it behaves on other Unity games?
    I was curious to know if the problem was specific to my Unity project setup so I made tests on other Unity games. I made my tests in fullscreen:
    I am surprised of such a difference.
    Can there be a difference of config that makes such a difference on both games?

    Ok, I will follow your advice and keep the default settings on all platforms then. Thanks for the tip.
     
  14. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks for the detailed info.

    I believe rather the difference is between the number of GameObjects rendered, and also possibly whether URP or built-in renderer is used - each GameObject needs populating a GPU buffer for rendering, glClientWaitSync() relates to that usage.

    One super hacky thing you can try is to take a generated uncompressed release build, and find where it has something like

    Code (JavaScript):
    1. function _glClientWaitSync(sync, flags, timeoutLo, timeoutHi) {
    2.     return GLctx.clientWaitSync(GL.syncs[sync], flags, convertI32PairToI53(timeoutLo, timeoutHi));
    3.   },
    4.  
    in the framework.js file, and then replace its contents with a function

    Code (JavaScript):
    1. function _glClientWaitSync(sync, flags, timeoutLo, timeoutHi) {
    2.     return 0x911C;
    3.   },
    4.  
    (or alternatively return 0x911A)

    That might have the effect of removing the GL waits altogether from the code, although whether that will help performance is a bit of a stretch.

    In any case, I've added a task to investigate this on the appropriate hardware on our task board. Hopefully we can improve performance on the Intel GPUs here.
     
    FOAG likes this.
  15. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Thanks for the hacky tip, I will try that and let you know how it goes :)

    Could you just tell me what this actually does?

    I guess that if there's a clientWaitSync it means that it's necessary? What could be the potential side effects?

    Thanks for adding the investigation on Intel GPU on your Task Board :)
     
  16. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    The change will stop the GL code from synchronizing the overwrite of GL buffers until they are actually freed up by the GPU. GPU drivers should be utilizing a shadow copy on writes to the buffers while they are still in the driver queue, but some GPU drivers don't do that, but they block instead of shadow copying, causing worse performance instead.
     
    FOAG, fxlange and jtiret like this.
  17. fxlange

    fxlange

    Joined:
    Dec 20, 2016
    Posts:
    45
    Hi @jukka_j, I just wanted to add how valuable it is to see how you approach the profiling here for webgl, I super appreciate you doing this. There is not much information on profiling webgl for Unity plus the fact that you can't connect the profiler remotely to webgl clients made it super hard for me to profile poor webgl performance (so I thought but you arn't using the unity profiler anyway). I don't want to hijack this thread with my own questions and will do my own tests first with what I learned here. Thanks a lot for that.

    But maybe with the current efforts from Unity for webgl clients and even (maybe) officially supporting webgl for mobile in a foreseeable future please consider releasing more unity+webgl specific resources on optimization and profiling approaches like showcased here.
     
    De-Panther and jtiret like this.
  18. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hi @fxlange

    No problem, I couldn't agree more that the information given by @jukka_j in this thread are very insightful, not only for me but for other Unity developers so I am very glad that my questions could lead to answers that could helped you too! I can say that I didn't find that kind of insightful information documented so I really appreciate that as well :)

    Hi @jukka_j

    So I tried the hack and even if clientWaitSync disappeared from the profile, the performance is very similar with a bad frame rate (and my computer being quite noisy). Here is the profile: https://share.firefox.dev/3yKviR6

    The URL where I hosted this version (with the hack) is here: https://app.dev.dinogaia.com/test-without-client-wait/
    You can see that I applied one of your suggestion on this file (hosted uncompressed): https://app.dev.dinogaia.com/test-without-client-wait/Build/build_webgl32.framework.js

    Screenshot 2021-05-28 at 13.21.47.png

    Both of the options (0x911C or 0x911A) give similar performance result.
    As a reminder, the regular version without the hack is here: https://app.dev.dinogaia.com/

    I see in the Flame Graph that frame rendering is sometimes triggered upon PVsync::Msg_Notify and sometimes not, but I guess it's normal because it always leads to a nsRefreshDriver:Tick.

    Screenshot 2021-05-28 at 13.27.18.png

    I don't find in the profil anything that can explain why it is so slow. Do you see something that could explain that?

    From your experience, is it common that I experience a much better performance in a Standalone build? I am wondering whether it will be a good option to offer a WebGL version of my game (even if I am convinced that it is very powerful to offer players to play directly from their browser).

    What I wanted to do to optimize performances was to reduce the devicePixelRatio (from 2 to 1 on Retina displays) but the text on the UI became quite blurry (however, it has a huge positive impact on performance!).

    So what I tried instead was to reduce the render scale of the URP setting which doesn't impact UI (from 1 to 0.6 for example) but it doesn't have much effect, performance remains bad. Do you know any other simple techniques that don't make the UI blurry but can have huge impact on performance?

    Again thanks a lot for your support and dedication
     
  19. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Looking at the new profile, removing the glClientWaitSyncs did have a large impact to CPU times.

    In the old profile CPU utilization was at 77%, whereas in the new profile, CPU utilization is down to 64%, so a (77-64)/77 = -16.9% reduction in CPU utilization. This is quite significant improvement.

    However like you mention, that improvement is not translating to real world gains, and overall performance remains unimproved. Looking at the profiles, the 16.9% of time that is optimized is now just shifted in Firefox profile to PWebGL::Msg_GetFrontBuffer - meaning that the code is now just waiting more to present. This confirms that the rendering is GPU bound, rather than CPU bound. This was also suggested by the fact that resizing the render target size changed the performance.

    What makes this glClientWaitSync business more complex is that on some other GPUs, not waiting for glClientWaitSync results in stuttering behavior due to subsequent glBufferSubData()s stalling the CPU-GPU pipeline. So we need to find a way to remove the glClientWaitSyncs in a way that does not regress other GPUs.

    Now when the rendering is GPU bound and resizing affects performance, there are two likely scenarios:
    a) GPU is simply rendering too many pixels, i.e. the app is fillrate bound,
    b) GPU is not necessarily rendering too many pixels, but the shaders in those pixels are too complex, i.e. the app is pixel shader ALU or memory bandwidth bound.

    One way to optimize would be to reduce the number of pixels rendered to tackle scenario a), like you are already doing. Some thoughts come to mind:

    This is unfortunately true, since DPR affects the overall rendering resolution. One thing to try here is to test if switching from bilinear filtering to pixelated/point filtering would give more acceptable results for the UI text to be more readable. This is controlled via a html page CSS style for the canvas element.

    Check out https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering

    When you write "doesn't have much effect", do you mean that it does not have much visual effect (for better or for worse), or it does not have much performance effect? If it does not affect visually, try to double check that the setting is working for WebGL, e.g. by setting it to 0.1 or something like that to use a really small intermediate render target.

    If setting the URP scale to 0.1 does not make any impact to performance, then either the GPU fillrate is really constrained if we're in scenario a), and rendering the UI fills too many pixels to cause a perf impact.

    Or if the issue is b), then it would be good to double check whether there exists some element in the app (either in the 3D scene, or in the UI) that taxes the GPU exceptionally badly.

    Another thing to double check is that URP MSAA is disabled. That can eat fillrate really badly.

    Typically we see CPU performance being 20%-30% worse in wasm compared to native, but here the issue is not a CPU bottleneck, so that does not apply. On GPU side we generally see performance being about the same, although given that newer GPU rendering specifications are not available on the web (looking towards WebGPU..), there are some corner cases where performance will be much worse on WebGL compared to native GL (e.g. transform feedback, memory mapping related synchronization). Though this should not be one of those cases, since the rendering here is very standard.
     
    FOAG and KamilCSPS like this.
  20. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks, much appreciated.

    We do struggle a bit to maintain documentation on various web development techniques that do exist on the web in general, and are somewhat common to web developers - but might not be common to native game and engine developers. E.g. web hosting, browser persistence and caching, security primitives, CDN load balancing and mirroring, and optimization.. there are a lot of web/JavaScript specific documentation out there, but those can be hard to connect to from within the Unity realm.

    We'll keep an eye out for good material to put out that would connect these two worlds together a bit better.
     
  21. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hi @jukka_j,

    Thanks for all these details!

    Sorry if this was unclear. I mean't it doesn't have much effect on performance. However, it does change the visual aspect. For example when I set this to 0.65 or 0.7, the game is degraded but remains visually acceptable. However, the performance remains almost the same. When setting to 0.1 the visual effect is not acceptable, performance is better but not as good as setting devicePixelRatio to 1. (sorry if my description lacks some measured facts but rather express my feelings)

    Will give it a try! Thanks.

    And what about reducing the resolution?
    I tested the game earlier using Bootcamp, which allows me run Windows on my Mac, and the performance was absolutely perfect (both with Edge and Chrome). I initially thought this was due to some sorts of Windows settings, but I quickly realized that the screen settings were not the same, in fact the resolution set up on Windows was 2x lower.

    This gave me the idea of just reducing the resolution of the WebGL canvas. It would be completely acceptable for me to have the game presented in a 2x lower resolution (being zoomed, I guess) if this can solve the problem of rendering too many pixels. If my understanding is correct I would just reduce the size of the WebGL's drawingbuffer. Maybe I could even find a way to scale up or down the UI in order for it to keep the same physical size.

    Basically I'd like my users to be able to play fullscreen, but with a game that would be zoomed in order for their computer not to render too many pixels.

    @jukka_j what do you think? Is reducing the resolution of my WebGL canvas something that could solve my problems while keeping an acceptable UI?
     
  22. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks, that is good information. If URP scale of 0.1 does not quite help the issue, compared to DPR of 1.0, that does suggest that it would be the overall pixel fillrate, and not just the 3D scene rendering fillrate, that is causing the performance issue. I.e. it is not the 3D scene shaders filling pixels that is taxing, but the amount of filling in 2D UI shaders that is taxing.

    Another way to double check that could be to simplify the 3D scene itself, and see if removing any of the scene contents has a big effect on improving performance.

    I think that is what adjusting devicePixelRatio should do: halving devicePixelRatio from the browser default should halve the actual rendered resolution. Now I realize that maybe the browser default devicePixelRatio was not 2, so setting it to 1 was not halving it, but it was actually shrinking it even more.

    You can visit https://johankj.github.io/devicePixelRatio/ on the browser to quickly get a reading of the default browser devicePixelRatio. Be sure to have the browser set to default 100% browser zoom level when visiting the page, since the browser zoom level affects the DPR value. If you then set the Unity page load devicePixelRatio value to half of that, it should achieve the same.
     
    FOAG likes this.
  23. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Thanks, I keep investigating if toggling off/on different elements has a significant effect on performance. I've implemented some sort of Debug Manager with shortcuts to do it at runtime in a WebGL build.

    I confirm that my Device Pixel Ratio is 2.

    However, zooming/reducing the resolution and reducing the device pixel ratio doesn't exactly have the same effect on my side (at least not on the UI and not on performance)

    With Device Pixel Ratio
    The game scale remains the same but the UI becomes blurry. Here is a before/after when updating the Device Pixel Ratio:

    With a pixel ratio of 2:
    Screenshot 2021-06-02 at 10.22.46.png

    With a pixel ratio of 1:
    Screenshot 2021-06-02 at 10.23.16.png

    By the way, I tried the CSS property to render the image as "pixelated". The rendering is not blurry but pixelated and not visually acceptable either :(

    With a different resolution

    However, when I have a different resolution on my computer (if I simply go in the settings of my computer and reduce the resolution), almost everything is scaled, including the OS' UI (except the dock), other applications, Browser's UI, etc.
    The WebGL canvas is also scaled.

    Here is what it looks like with 2 different resolutions on my computer. I took photos because it helps better understanding the physical differences between the two.

    With 2560x1440 (x2 pixels to render because of devicePixelRatio) :
    2560x1440.png

    With 1600x900 (x2 pixels to render because of devicePixelRatio) :
    1600x900.png

    Both photos were done on the same OS, screen and computer, but with a different resolution.

    In both cases, the visual aspect of the UI is very good, but in the first one (with the biggest resolution) the performance is just very bad whereas in the second one it is pretty descent.

    Is there any way to achieve the same with WebGL in Unity? If I could do that, I think that every performance issue would go away with a good visual aspect.

    One thing that confuses me however is that the only thing that is really scaled is the UI on the photos above. So we could conclude that these issues come from the UI… (as suggested in your previous answers). However, if I completely disable the GameObjects having UIDocument components (I am using UI Toolkit), the UI disappears from the screen, but the performance problem is still there.

    It is very confusing, even if I feel that we may find what's going wrong at some point.

    Again, @jukka_j, thanks a lot for taking this time to help me. I appreciate this so much. :)
     
    Last edited: Jun 2, 2021
  24. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Hmm, I wonder if the monitor is doing some kind of more intelligent filtering/antialiasing in lower resolution modes.

    If your monitor is 3840x2160, can you post a photo in 3840x2160 mode where you set devicePixelRatio to 1 to make the game render in 1920x1080 mode? Also in that mode, can you double check that the rendering is actually happening to a 1920x1080 canvas? You can do that e.g. by opening the web page console and printing

    document.querySelector('#unity-canvas').width
    document.querySelector('#unity-canvas').height

    Or by observing in the inspector window.

    Also, can you post a second photo where you set the rendering to pixelated?

    Then, can you change the devicePixelRatio back to default, and set monitor to 1920x1080 mode, and post a photo of the display results in that mode? I am curious to see what this mode looks exactly in comparison of the manual downscaled results. To my understanding a "halve-by-two" display scaling would be a direct 2:1 downfilter, but maybe there is something different in action here.
     
    FOAG likes this.
  25. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    My default resolution is 2560x1440. Unfortunately, I can't exactly halve this resolution. The minimum resolution MacOS will allow me is 1600x900. So I have done screenshots and photos in both resolutions.

    For all screenshots and photos, settings have been checked by adding a box on the top right of screen:
    Screenshot 2021-06-02 at 14.58.42.png

    Where:
    • Screen Size is the value of window.screen.width and window.screen.height
    • Inner Size is the value of window.innerWidth and window.innerHeight
    • Canvas Size is the canvas element's width and height attributes (document.querySelector('#unity-canvas').width and .height)
    • Image Rendering is the canvas element's image-rendering style value.
    • Device Pixel Ratio is self explanatory.

    Resolution: 2560x1440, Device Pixel Ratio 1 and image-rendering to the default value
    high-res-dpr-1-rendering-auto-screenshot.png
    => Here is how it looks in photo instead of screenshot.

    You can see that canvas size is exactly equal to inner size because device pixel ratio is 1. When it's 2, the canvas size is 2x larger.

    The photo doesn't make it obvious that the text is blurry, but in fact it is.

    Resolution: 2560x1440, Device Pixel Ratio 1 and image-rendering to "pixelated"
    high-res-dpr-1-rendering-pixelated-screenshot.png
    => Here is how it looks in photo instead of screenshot.

    It might not be obvious on the screenshot that the text rendering isn't right depending on how you zoom on it, but when you look on the screen, it's not right. However it appears clearly on the screenshot that the icons (Apple and Discord) are too much pixelated.

    Resolution: 1600x900, Device Pixel Ratio 2

    low-res-dpr-2-rendering-auto-screenshot.png
    => Here is how it looks in photo instead of screenshot.

    Display in this resolution is good.

    ------

    I hope you'll be able to have a taste of the differences as photos don't always reflect how it really looks like and screenshots are not always good either because they are not displayed the same way (I mean, when I take a screenshot of a 100x100 area of the screen, the resulting file is 200x200.

    Interestingly, in low resolution with a Device Pixel Ratio of 2, there are more pixels to render than in high-res with a DPR of 1 (because low res is not half high res but a little more). However, the performance is even better in that case (low resolution with more pixels to render at a DPR of 2 rather than high resolution with a DPR of 1). I am still very confused…
     
  26. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    I have develop a feature to adjust some settings directly from JavaScript (in order to be able to keep adjusting while all UI on Unity is disabled). They are visible on https://app.dev.dinogaia.com

    Screenshot 2021-06-03 at 15.55.31.png

    The idea was to change the URP scale, the DPR and to see how it impacts FPS.
    I have also created shortcuts in Unity to be able to disable the UI and all the GameObjects on the scene:
    - SHIFT + I to toggle the UI
    - SHIFT + R to toggle Game Objects with a Renderer component
    - SHIFT + B to toggle the background

    Some results are quite surprising.


    DPR=2 / URPScale=1 / All Objects and UI visible
    => FPS ~ 10

    When running in full screen with the highest DPR and URP Scale and all objects visible is bad, the FPS:
    Screenshot 2021-06-03 at 15.51.00.png

    DPR=2 / URPScale=1 / All Objects visible but the UI is removed
    => FPS ~ 10 (same as before)

    Screenshot 2021-06-03 at 15.51.17.png

    DPR=2 / URPScale=1 / All Objects, background and UI removed
    => FPS ~ 22 (better but still very bad)


    The blue color is the default one set up in the camera. So basically, with nothing rendered, I wonder how I can get such as bad performance (here is a profile showing how it goes).
    Screenshot 2021-06-03 at 15.51.34.png

    DPR=2 / URPScale=1 / With the UI only
    => FPS ~ 16


    Showing the UI has a little impact…
    Screenshot 2021-06-03 at 15.51.46.png
    (others tests to come in the next message)
     
    Last edited: Jun 3, 2021
  27. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    DPR=2 / URPScale=0.01 / Everything hidden
    => FPS ~ 28 (better but still very bad)

    Reducing the URP scale to 0.01 has basically no impact (of course, every objects are hidden so this looks normal)
    Screenshot 2021-06-03 at 15.53.23.png

    DPR=0.01 / URPScale=1 / Everything hidden
    => FPS ~ 60 (perfect)


    When reducing the DPR to 0.01, the FPS is good. The canvas size is only 26x13 so just a few pixels to render.
    Screenshot 2021-06-03 at 15.52.47.png

    DPR=2 / URPScale=1 / Everything hidden / Window size reduced
    => FPS ~ 60 (perfect)


    Reducing the window's size has the same effect as reducing the DPR. The canvas is smaller and it renders well.
    Screenshot 2021-06-03 at 15.52.21.png
    And actually it renders well with a good FPS also if I enable everything on the scene:
    Screenshot 2021-06-03 at 16.12.03.png


    By the way, one of my early tester couldn't run the game which was too slow and could resolve the issue by enabling an experimental feature in Chrome (chrome://flags/#ignore-gpu-blocklist)

    « Overrides the built-in software rendering list and enables GPU-acceleration on unsupported system configurations. – Mac, Windows, Linux, Chrome OS, Android
    #ignore-gpu-blocklist »


    That has no effect on my side (and even if it did it's an experimental feature), but I mention it in case it would ring a bell.
     
    Last edited: Jun 3, 2021
    KamilCSPS likes this.
  28. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    I was so intrigued by these results that I decided to run the experiment on a fresh project using URP. What I did was to create a new project using Unity 2020.3.10f1, choosing the default URP template. I just removed every GameObjects and lights from the scene (in order to just see the default Camera background) before running the experiment. Guess what, the performance is almost the same. :confused:
    (I just added the Debug C# script that communicates with JavaScript to apply the settings and provide FPS data)

    Maximum screen size with highest Device Pixel Ratio and URP Scale Rate.
    => FPS ~ 24

    (the image is just the default camera background)
    Screenshot 2021-06-03 at 21.26.16.png

    Lower window size with highest Device Pixel Ratio and URP Scale Rate.
    => FPS ~ 60


    When reducing the screen size, everything runs properly.
    Screenshot 2021-06-03 at 21.26.55.png
    In the end it looks that it has nothing to do with the specifics of my project.

    I come to same conclusion: I need my canvas to be 1.5 / 2x smaller to have acceptable performance. However, I need to do so while keeping a proper rendering for the UI at least. When achieving a smaller canvas through reducing window.devicePixelRatio, the result is much less acceptable than when just changing the resolution via my OS settings. In both cases, canvas is smaller but when this is due to OS resolution I have a window that is full screen with non-blurry/pixelated interface and game.

    I guess there might be some hardware incompatibility somewhere as well, as my GPU card is not supposed to be very old so it should support single-color pixel games at 60 FPS on the Web :D
    But I guess this kind of issues can't be solved anytime soon so scaling the game is OK for me in the meantime.

    @jukka_j I know that you are working very hard to follow-up with every one on the forum and that you have helped me a lot already but I'd be very curious to get your point of view on these new data. And also if you have any (other) idea regarding how I could scale the game to improve performance. Maybe there's some other hidden setting that could do that in Unity or in JavaScript?
     
  29. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    Thanks, very detailed information.

    This sheds an important clue to where the performance bottleneck is coming from. It turns out that the slowdown is in pure GPU fillrate, and related to browser's own upscaling compositing. The difference between these two modes is:

    a. display at native 5120x2880, but devicePixelRatio halved so that Unity renders to ~2560x1440, and browser upscales it to the 5120x2880 resolution, vs
    b. display at downscaled 2560x1440, devicePixelRatio at 1:1 so that Unity renders again to ~2560x1440, and browser also produces WebGL output at 2560x1440, internal display hardware circuitry upscales to 5K to fill the screen.

    Like you also mentioned, Unity does the same amount of pixel work in the engine in both cases (in case b even a little bit more given the inexact rounding), but the difference is that in case a the browser still has GPU work to submit to perform a 1440p->5K upscaling. It looks like that upscaling is what constrains the available bandwidth. That is why we see scenario b being more performant.

    The CSS directive "image-rendering: pixelated" does have a chance of improving fillrate performance if the fillrate is ALU bound, that should help browser compositing a little bit. Although if the fillrate is texture memory bandwidth bound, then pixelated setting won't make any difference.

    Also looking at the photos, I believe the slight increase in pixel counts is what is making the text on 3200x1404 look better than 2560x1213 scenarios.

    The test with an empty blue scene further confirms that this is a browser compositing bottleneck. However gut feeling says that the Intel Iris Plus Graphics should not be *that weak* that it couldn't do an empty composit at 5K @ 60fps.

    Something to try is to poke the WebGL context creation settings to see if there would be anything there that would affect performance. Check out

    https://docs.unity3d.com/2020.1/Documentation/Manual/webgl-graphics.html

    with the line

    Code (JavaScript):
    1. config['webglContextAttributes'] = {"preserveDrawingBuffer": true}; // Add this line to the index.html file in a WebGL Template
    If we take a peek at WebGL specification of the different values that webglContextAttributes accepts, at https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2 , there are a couple of interesting fields to test. I am curious for example if the following options would cause any change in performance:

    Code (JavaScript):
    1. config['webglContextAttributes'] = {
    2.   "alpha": true,
    3.   "depth": true,
    4.   "stencil": true, // also interesting to test 'false'
    5.   "antialias": false,
    6.   "premultipliedAlpha": true,
    7.   "preserveDrawingBuffer": false,
    8.   "powerPreference": "high-performance",
    9.   "failIfMajorPerformanceCaveat": true,
    10.   "desynchronized": false};
    11.  
    This kind of change is good to be tested on both Firefox and Chrome.

    You can double check the context attributes from web page console by running

    Code (JavaScript):
    1. document.querySelector('#unity-canvas').getContext('webgl2').getContextAttributes()
    If adjusting none of those settings has any effect, then it looks like something that we should report it as a browser bug.

    Just to double check (sorry I forgot if we did already), if you do a native macOS build of the project in full screen 5K, does that run with good performance? If it does, then it is certainly a browser compositing issue.

    If the above webglContextAttributes test does not help, I would go ahead and report it as a performance bug to Unity. We can have QA test the same hardware and route the issue forward to Google and Mozilla to tackle if it turns out like it does that the performance issue lies with browser compositing.
     
    FOAG likes this.
  30. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hello @jukka_j,

    I have tested all your suggestions but unfortunately none of them has a significant impact on performance :(, nor does it seem to affect anything else visually.

    Yes the performance is much much better with Standalone Mac. In full screen on the 5K it's not 100% smooth though, but it's acceptable and much better than in WebGL.

    @jukka_j Just for my curiosity, now that I have added stats (FPS, etc.) at the top right of my app, what do you see on your computer, does it run at 60 FPS or lower? https://app.dev.dinogaia.com/ (you can check the top-right black box once the game has loaded, as below)

    Screenshot 2021-06-10 at 09.45.31.png
     
  31. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    591
    Just my curiosity - what is the Max Texture Size on the Mac with the retina display?
    https://webglreport.com/?v=2
    Other stats might also be interesting
     
  32. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hello @De-Panther,

    The Max Texture Size is 16384 on my Mac.

    I have also screenshoted other statistics in case you (or someone else) would need it, they are attached to this message.
     

    Attached Files:

  33. thomasu22

    thomasu22

    Joined:
    Oct 17, 2019
    Posts:
    1
    Hello. What now is the issue and how do I solve it? Since I am experiencing the same problem and apparently others as well: https://iceicepingu.itch.io/escape-the-narrative (I picked it at random and did not look very long though). Is this a fault from Unity, the Browser or myself? I already had this issue with 2020.3.12 and updating to 2021.1.19 did not fix it. It is also very easy to recreate this bug with just
    1. Create an empty 3D project (2021.1.19)
    2. Adding URP
    3. Adding a sprite (2048x683) and a particle system so it is nicer to look add (I am not sure if it is necessary)

    Is there at least a hacky solution or do I just have to prohibit fullscreen mode?
    Thank you for your help
     
  34. pohype

    pohype

    Joined:
    Apr 12, 2019
    Posts:
    72
    I also encounter this issue on mobile-only (i guess because it's more visible), it takes the form of a constant 300ms overhead on each frame that is visible in the profiler as "OnDemandRendering.GerRenderFrameInterval()".
    I didn't have this issue before upgrading to Unity 2020 (was working perfectly in Unity 2019), hope this get fixed soon !
     
    Last edited: Sep 27, 2021
  35. aasiq

    aasiq

    Joined:
    Dec 29, 2016
    Posts:
    16
  36. jtiret

    jtiret

    Joined:
    Nov 11, 2020
    Posts:
    63
    Hello all,
    For @aasiq and others wondering: unfortunately I wasn't able to solve the issues I had on the WebGL version of my game :(
    I had to postpone this version because it wasn't acceptable enough in terms of performance. Instead, I decided to launch on mobile (iOS and Android). I may launch on desktop and laptop in the future, but I will probably go with standalone Windows and Mac apps instead of WebGL as the performance are a little more acceptable.

    PS: all the tricks and tips I found that may help you improve the performance are already detailed in this topic, I didn't find anything else for now unfortunately…
     
    elyesYourArt likes this.
  37. aasiq

    aasiq

    Joined:
    Dec 29, 2016
    Posts:
    16
    That's unfortunate. It would be great if Unity recognises and addresses this issue on WebGL. Thanks for the insights.
     
  38. bindon

    bindon

    Joined:
    May 25, 2017
    Posts:
    21
    Sometimes WaitForTargerFPS at around 11 milli seconds gives me an acceptable framerate.

    When it is working properly waitForTargetFPS about 11ms.png

    Then sometimes I do a webgl build and I get WaitForTargetFPS over ~60 milli seconds or higher

    When it is NOT working waitForTargetFPS about 60ms or more.png

    Endless trials of different permutations and combinations of settings like VSync, and adding and removing various things in the code that I thought might be making a difference, have not yet enabled me to find out what makes some builds WaitForTargetFPS become so unacceptably high, while other times it is a good 11 milli seconds.
    I'm wanting to believe that I can come to understand and control this, but at the moment it is seeming to be inscrutable.

    EDIT:
    Ah I think I figured it out. It is because:
    (1) the profiler does not show what is going on on the GPU
    (2) whatever VSync setting you choose to specify in your app may easily be over-ridden at the OS level of whatever device you are running on - eg. if you are running in a Chrome browser on a PC like I was, the relevant VSync setting was the one in the NVidia control panel for Chrome browser
     

    Attached Files:

    Last edited: Feb 15, 2023
    OmarVector likes this.
  39. OmarVector

    OmarVector

    Joined:
    Apr 18, 2018
    Posts:
    144
    This is exactly the case for us, but on webgl mobile, and only happen on certain GPUs not all mobile GPU produce the same issue
     
  40. Bonelesszebra

    Bonelesszebra

    Joined:
    May 25, 2022
    Posts:
    1
    Hi, anyone coming to this thread looking for answers like I did; This is a unity problem. My webGL build on my pc couldn't get more than 8fps at fullscreen. But I tried it on 3 different PC's all with different GPUs and had no issues at all, even on very old GPUs. I have an rtx 3060 and couldn't get more than 8fps. There is a an issue with this version of unity webgl builds (apparently) that some GPUs just seem to struggle with for reasons beyond my knowledge. I spent hours and hours attempting to optimize and trying every single permutation using dev builds and the profiler. Even with a project with nothing but a camera and a FPS counter i couldn't break 15fps. (my game is an extremely simple 2D pixel art game and not demanding at all.)

    If you have this issue, don't waste hours and hours like I did, try it on a different PC with a different GPU.
     
  41. KamilCSPS

    KamilCSPS

    Joined:
    May 21, 2020
    Posts:
    450
    You should still try to send a repro case to QA. Sounds like a GPU driver issue - complete clean up of drivers and reinstall might do the trick or a different version of the drivers. Or even OS config, due to monitor refresh rates etc.
     
  42. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    591

    Sounds like a specific issue of the browser on your device. What browser and version are you using, on what OS and version?
    I heared about issues like that with other frameworks as well.

    Browsers based on Chromium had some issues after replacing the backend render engine on mac.