Search Unity

Shader keyword limit

Discussion in 'Shaders' started by LukasCh, Aug 15, 2018.

?

Which solution works best for you?

  1. 1

    47.7%
  2. 2

    6.8%
  3. 3

    45.5%
  1. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Hello folks!

    Recently we seen some users experiencing issues with limited keyword count. As result we decided it might be a could time to revisit this problem again.

    So for some who do not know about the global keywords limit, here is quick explanation.
    Basically when you declare any new keyword in shader (etc. multi_compile, shader_feature) or with scripting API (etc. Shader.EnableKeyword, Material.EnableKeyword...) we actually assign unique index from 0 to 255 and store it as global dictionary between the name and index. This allows us to store enabled keywords as bitmask, this way increasing all keyword related operations significantly. However as some of you already aware it restricts project from having more than 256 unique keywords across all the shader. Usually it is not that easy to hit the cap, but that is not the case once you start to rely on third party packages.

    For this reason we were thinking about possible solutions for this issue and we decided it would be great to get feedback from you guys.

    1) Increase keyword count to 1024. Well this is actually the simplest solution and we already did this multiple times before.
    Advantages - we do not break the old functionality.
    Disadvantage - this affects keyword related performance, but we seen regression only if project actually uses more keywords.

    2) Make keyword completely local. It means every shader can have 256 unique keywords. However functions that modify keywords globally (etc. Shader.EnableKeyword, CommandBuffer.EnableShaderKeyword), must be removed or changed to simulate old functionality by patching local map.
    Advantages - we keep shader variant API intact, we get completly get rid of global keywords.
    Disadvantage - functions that change keywords globally must be removed or has to get very heavy internal change (That might not work exactly same in all cases as it would be simulated with local keywords).

    3) Add local keywords as additional functionality on current system. So basically hybrid mode to support local and global keywords at the same time. Idea is to leave 192 keywords for global and 64 for local per shader.
    Advantages - we keep old functionality intact.
    Disadvantage - we have to introduce new shader API that would allow specifying which keywords as local.
    Current idea is to deprecate multi_compile/shader_feature and introduce new unified pragma generate_variants that would have some additional options.
    For example:
    #pragma multi_compile A B == #pragma generate_variants nostrip global A B == #pragma generate_variants nostrip A B

    #pragma shader_feature A B == #pragma generate_variants strip global A B == #pragma generate_variants A B

    #pragma generate_variants strip local A B

    #pragma generate_variants nostrip local A B


    We currently have option 3 implemented, but not publicly available. The option 2 still requires a bit investigation, because it would require fundamental changes of keyword system.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    6,999
    I suspect option 1 will be the option most people will choose, but I suspect that option will just lead to a post in a few years of "should we increase the keyword count to 2048?".

    Option 2 seems bonkers, global keywords are exceptionally useful.

    Option 3 feels like the best option, though obviously won't solve the problem for most people until assets get updated and people learn the new paradigm.
    Also, why wouldn't #pragma shader_feature AB == #pragma generate_variants strip local A B ? I'm not sure I've seen any assets that try and change shader feature keywords globally as, at least in my mind, I already treat them as "local" keywords. Granted this has the potentially to break old assets, but it's already so dangerous to try to change potentially stripped keywords I would assume most people change to using multi_compile after finding shader_feature didn't work in a standalone build, and most people don't know about ShaderVariantCollections still.



    Somehow I can still imagine a future where people ask for local and global 1024 keywords ... we'll ignore the multiple gigabyte of shader variants this option leads to, and that static branches are basically free on modern GPUs.
     
  3. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    @bgolus, thanks for respond and those who voted in poll.

    We come up with different approach for third option. What differs - global keyword limit will be left intact to 256 and we will add additional 64 for local and instead of introducing new user variant directive (etc. generate_variants, propose above), we will expose per shader in shader import settings if user wants to treat their shader_feature or/and multi_compile as local (Will be off by default).
    This solution will be much safer choice as it would not only leave old functionality intact, but at the same time will allow some users to use it and isolate it per shader.

    In the future we still thinking about new user variant directive that would encapsulate local/global/multi_compile/shader_feature functionality (As the naming for shader_feature and multi_compile was not ideal, especially when they both have very similar functionality), but we also want it to cover the unneeded variant striping (That is currently big issue of variant explosion)
     
  4. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,032
    @LukasCh ,

    What ultimately happened with this?
     
  5. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    We decided to drop this idea, as it will break consistency with our shader compilation. For this reason we decided to introduce just varations of shader directives shader_feature_local and multi_compile_local.

    Currently local keywords landed in 2019.1 and will be available for alpha users. Here is more information about it https://docs.google.com/document/d/156MgqojKIgWgrpJLJ0WgD8pVzG0A0T42e3wr0d0oaLg/edit.
     
  6. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,032
    @LukasCh ,
    Thanks for responding. I found a way to row back on the sheer number of shaders in my project in the meantime... ;)
     
  7. FarNiche

    FarNiche

    Joined:
    Jul 24, 2014
    Posts:
    6
    Where Do Those Shaders Come From?
    I've found that many people do many things in many different ways to get what they are trying to express to work as they intend. As a test I've loaded over 555GB of asset packages into one Unity project while working in 3D. Doing that, I have also reached the 256 shader definition limit and at times have no idea of who added what to my shader list. That project only runs in Play-Mode on a fast Solid State Drive not a Disk Drive. I've tested that also. Even so, I'm pulling for the Asset Store creators/contributors creativity. I would opt for a 1024 shader definition limit as the way to go but also a way to see whom added which shaders from where. Having that shader info documented by the contributor might be a Best Practice, but maybe a set of log files built from the Unity Game Engine itself could automate that procedure. Thanks for the post.
     
  8. GameDevCouple_I

    GameDevCouple_I

    Joined:
    Oct 5, 2013
    Posts:
    1,762
    I am dead excited to try this out! Didnt realise they were going to be added so soon!
     
  9. nbd

    nbd

    Joined:
    Aug 18, 2014
    Posts:
    33
    why not make the keyword limit configurable while a good solution is implemented? That way we will at least get to test our projects quickly.
     
  10. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Could you elaborate? I'm guessing you mean changing global keyword limit between 1-256?

    If you mean just plainly increasing keyword count while local keywords are developed. Well the biggest reason is that by increasing keyword count will result in performance decrease (It is not much, but it is static increase that will never go away). Even after the local keywords, we could not reduce keyword count as most of the user would depend on it by now (Even now, I would say 256 of global keywords is way too much, if we would had local keywords by now).
     
    Last edited: Dec 21, 2018
  11. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Hello, another batch of changes related to local keywords landed in 2019.1.0a14.
    These includes:
    - Fix for subshaders not correctly working with local keywords
    - Fix for material properties copying
    - Other small fixes
    - Moved 38 of unity builtin keywords from global to local. In result unity now only occupies 38 global keywords by default instead of 79
    - Added new button in shader inspector to show what global and local keywords it uses
     
    twobob, MaxProude and Duffer123 like this.
  12. MaxProude

    MaxProude

    Joined:
    Feb 24, 2013
    Posts:
    141
    Does this improve surface shader compilation time as well? I have a big shader with many shader variants, that I've tested independently to be working, but if they are all added into the shader it compiles until it fails. It seems like I have to always disable one feature no matter which one it is. The strange thing is that it doesn't tell me what the problem is, since the error message is very cryptic.
     
  13. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Well local keywords feature was not designed to shader compilation purposes, so it should no affect it in any way (If it is slower, it means it is a bug). Could you post the shader I would gladly look into it.
     
  14. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Oh I though it is related to local keywords, if it is really not - could you make new thread with this and poke me in there. I do not want to mix threads that would result only in confusion.
     
    MaxProude likes this.
  15. MaxProude

    MaxProude

    Joined:
    Feb 24, 2013
    Posts:
    141
    Thanks! I've deleted the original post and moved it here.
     
  16. nbd

    nbd

    Joined:
    Aug 18, 2014
    Posts:
    33
    Sorry, been a while. I meant to make the keyword count a configurable property, perhaps in the project settings. The default value of the property would be 256. But the developers should be able to configure it to be anywhere between 0 to 1024 perhaps. the upper limit would be a hard limit with comments suggesting that its an interim solution and that it would be deprecated in favor of local keywords. Developers will have to go the way of local keywords to realize performance increases anyway(if they feel its significant). This will give developers some time to plan for localizing their keywords. I don't know if its doable, but I think it will make it easier for us. Thanks.
     
  17. nbd

    nbd

    Joined:
    Aug 18, 2014
    Posts:
    33
    @LucasCh,

    Any comments on the above? Thanks.
     
  18. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    Oh okey I understand what you mean now, we had some idea before the local keywords. However there is few reason why we decided to drop it:
    1) In unity all keyword variations are packed from strings array into 256 bit size integer (This is where limits comes) and in global map strings are stored. For configurable keyword limit we would had two solutions:
    a) In every code part make this integer size configurable, with this we would lose performance from build time optimisations.
    b) in every code part up this integer to maximum limit (etc. 1024), so in the end we would have some behaviour as just simply increasing the maximum.
    2) I fear that users would set it always to maximum to avoid headache in future (Even though if we had default like 256). In the end it would be simply another increase of global keyword count.
    As you mentioned before, to use this feature as a transition to local keywords. I believe it could bring more harm as we might end up supporting two ways and reducing limit back to 256 would be impossible.
     
  19. nbd

    nbd

    Joined:
    Aug 18, 2014
    Posts:
    33
    No problem. Thanks for the info.
     
  20. GorkaChampion

    GorkaChampion

    Joined:
    Feb 6, 2018
    Posts:
    102
    So...Whats the solution to all of us that reached the 256 limit? Any update soon? We can't download more assets on the store and also I have to delete same of then because I get the error 256 limit very often, so basically it's quite hard to keep working in our project.

    On the other hand HDRP will have the same limit?

    Thanks
     
    Matro likes this.
  21. Matro

    Matro

    Joined:
    Mar 15, 2013
    Posts:
    38
    I ask the same question what do we do when we hit the 256 limits?
    I have not found anything on how to manage this other than the asset Shader Control, I am not opposed to buying another asset if that is the only solution but I can say that is kinda dumb if removing other assets that I don't need will solve it. I have many assets that I have bought but if I can strip out the parts I don't need it will be better overall for any project.
     
  22. Tyrant99

    Tyrant99

    Joined:
    Dec 6, 2018
    Posts:
    3
    If we were to use only the built in HDRP shaders in a project, it would look something like this:

    Keyword Count:
    Layered Lit = 108
    Lit = 86
    Terrain Lit = 56
    Lit Tessellation = 71
    Layered Lit Tessellation = 98
    Decal = 8
    Unlit = 29

    Total = 456

    It's hard to see how the 256 shader keyword cap will come anywhere close to meeting the needs of the new SRPs.

    Let me know if I'm misguided in my assessment.
     
    Last edited: Apr 5, 2019
  23. Lynxed

    Lynxed

    Joined:
    Dec 9, 2012
    Posts:
    46
    Is this taken into account in ShaderGraph in 2019.1? I'm on 2018.3 and I have a very big shader (art direction request) , which is now stored in "Failed to complie", because of 256 keyword limit. Will moving to 2019.1 help?
     
  24. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    353
    I rely on many 3rd party assets for my project. I recently added one more and noticed that one of my older shaders no longer compiles. Is this the case when you go over the keyword 256 limit?

    If so, how to I check all shaders for keywords in my project so I can remove the ones I don't need?

    Btw, I'm on Unity 2017.4.24f1
     
  25. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    890
    A lot of those are platform and feature dependent keywords that should be stripped on build, no?
    I'd imagine HDRP will also start to make use of this local keywords feature as time goes on too.
     
  26. 30035172

    30035172

    Joined:
    Jun 25, 2016
    Posts:
    4
    Please increase the limit....
     
  27. AndreasO

    AndreasO

    Joined:
    Sep 25, 2012
    Posts:
    90
    Yes, we need more control over this. 256 is not enough.
     
  28. LukasCh

    LukasCh

    Unity Technologies

    Joined:
    Mar 9, 2015
    Posts:
    68
    HDRP uses local keywords so that should be fine

    What version you are using? As HDRP uses local keywords and Lit shader actually only uses 20 global keywords (~6 of them builtin) and most of these keywords reused in all the shaders that you described.

    You can try local keywords, very simple way to try it just replace all shader_feature -> shader_feature_local in your project and restart unity. This should be safe any easy way to try them and see if it helps
     
  29. Lynxed

    Lynxed

    Joined:
    Dec 9, 2012
    Posts:
    46
    Thanks! That company fired me like 3 months ago, but i'll give it a shot next time.