public static ShaderParsedCombinations ParseShaderCombinations(Shader shader, bool usedBySceneOnly, bool withLog = true)
        {
            if (shader == null || !ShaderUtils.HasCodeSnippets(shader))
            {
                return(null);
            }
            var  assetPath     = AssetDatabase.GetAssetPath(shader);
            var  deps          = AssetDatabase.GetDependencies(assetPath);
            long lastWriteTime = 0;

            for (int i = 0; i < deps.Length; ++i)
            {
                var fi = new FileInfo(deps[i]);
                if (fi.Exists)
                {
                    if (fi.LastWriteTime.ToFileTime() > lastWriteTime)
                    {
                        lastWriteTime = fi.LastWriteTime.ToFileTime();
                    }
                }
            }
            ShaderParsedCombinationsItem item;

            if (s_ShaderParsedCombinationsCache.TryGetValue(shader, out item))
            {
                if (item.lastWriteTime != lastWriteTime)
                {
                    s_ShaderParsedCombinationsCache.Remove(shader);
                }
                else
                {
                    return(item.data);
                }
            }

            ShaderParsedCombinations result = null;

            try {
                var fixedShaderName = shader.name.Replace('/', '-');
                var combFilePath    = String.Format("{0}/ParsedCombinations-{1}.shader", GetProjectUnityTempPath(), fixedShaderName);
                if (File.Exists(combFilePath))
                {
                    File.Delete(combFilePath);
                }
                Func <String, String[]> keywordsSpliter = src => {
                    var srcKeywords = src.Split(' ');
                    var dstKeywords = new List <String>();
                    for (int j = 0; j < srcKeywords.Length; ++j)
                    {
                        var x = srcKeywords[j].Trim();
                        if (!String.IsNullOrEmpty(x) && !dstKeywords.Contains(x))
                        {
                            dstKeywords.Add(x);
                        }
                    }
                    if (dstKeywords.Count > 0)
                    {
                        return(dstKeywords.ToArray());
                    }
                    return(null);
                };
                ShaderUtils.OpenShaderCombinations(shader, true, withLog);
                if (File.Exists(combFilePath))
                {
                    var lines = File.ReadAllLines(combFilePath);
                    ShaderParsedCombinations.Snippet curSnippet = null;
                    for (int i = 0; i < lines.Length; ++i)
                    {
                        var line = lines[i];
                        if (String.IsNullOrEmpty(line) || Char.IsWhiteSpace(line[0]))
                        {
                            continue;
                        }
                        Match match = ShaderParsedCombinations.REG_FILE_HEADER.Match(line);
                        if (match.Success)
                        {
                            if (match.Groups.Count > 1)
                            {
                                int num;
                                if (int.TryParse(match.Groups[1].Value, out num) && num > 0)
                                {
                                    result          = new ShaderParsedCombinations();
                                    result.shader   = shader;
                                    result.snippets = new List <ShaderParsedCombinations.Snippet>(num);
                                }
                            }
                        }
                        else if (result != null && (match = ShaderParsedCombinations.REG_SNIPPET_ID.Match(line)).Success)
                        {
                            if (match.Groups.Count > 2)
                            {
                                int id;
                                if (int.TryParse(match.Groups[1].Value, out id))
                                {
                                    int bits;
                                    if (int.TryParse(match.Groups[2].Value, System.Globalization.NumberStyles.HexNumber, null, out bits))
                                    {
                                        var snippet = new ShaderParsedCombinations.Snippet();
                                        curSnippet           = snippet;
                                        snippet.id           = id;
                                        snippet.platformBits = bits;
                                        result.snippets.Add(snippet);
                                    }
                                }
                            }
                        }
                        else if (curSnippet != null && (match = ShaderParsedCombinations.REG_SHADER_FEATURE_KEYWORDS.Match(line)).Success)
                        {
                            if (match.Groups.Count > 1)
                            {
                                var keywords = keywordsSpliter(match.Groups[1].Value);
                                if (keywords != null)
                                {
                                    curSnippet.shader_features = keywords;
                                }
                            }
                        }
                        else if (curSnippet != null && (match = ShaderParsedCombinations.REG_MULTI_COMPILE_KEYWORDS.Match(line)).Success)
                        {
                            if (match.Groups.Count > 1)
                            {
                                var keywords = keywordsSpliter(match.Groups[1].Value);
                                if (keywords != null)
                                {
                                    curSnippet.multi_compiles = keywords;
                                }
                            }
                        }
                        else if (curSnippet != null && (match = ShaderParsedCombinations.REG_BUILTIN_KEYWORDS.Match(line)).Success)
                        {
                            if (match.Groups.Count > 1)
                            {
                                var keywords = keywordsSpliter(match.Groups[1].Value);
                                if (keywords != null)
                                {
                                    curSnippet.builtins = keywords;
                                }
                            }
                        }
                        else if (curSnippet != null && (match = ShaderParsedCombinations.REG_VARIANTS_NUM.Match(line)).Success)
                        {
                            if (match.Groups.Count > 1)
                            {
                                int num;
                                if (int.TryParse(match.Groups[1].Value, out num) && num > 0)
                                {
                                    curSnippet.variants = new List <String[]>(num);
                                }
                            }
                        }
                        else if (curSnippet != null && line.StartsWith(ShaderParsedCombinations.TAG_NO_KEYWORDS_DEFINED))
                        {
                            if (curSnippet.variants != null)
                            {
                                curSnippet.variants = null;
                            }
                        }
                        else if (curSnippet != null && curSnippet.variants != null)
                        {
                            var keywords = keywordsSpliter(line);
                            if (keywords != null)
                            {
                                curSnippet.variants.Add(keywords);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Debug.LogException(e);
            }
            s_ShaderParsedCombinationsCache.Add(shader,
                                                new ShaderParsedCombinationsItem {
                data = result, lastWriteTime = lastWriteTime
            });
            return(result);
        }
        public String Dump()
        {
            String result;
            var    sb = new StringBuilder();

            sb.Append(ShaderUtils.DumpShaderPasses(shader));

            if (snippets != null && snippets.Count > 0)
            {
                sb.AppendFormat("// Total snippets: {0}", snippets.Count).AppendLine();
                sb.AppendLine();

                for (int i = 0; i < snippets.Count; ++i)
                {
                    var snippet = snippets[i];
                    sb.AppendFormat("// Snippet #{0} platforms {1:x}:", snippet.id, snippet.platformBits).AppendLine();
                    sb.AppendLine();

                    if (snippet.shader_features != null && snippet.shader_features.Length > 0)
                    {
                        sb.AppendFormat("Keywords stripped away when not used:\n\n{0}", String.Join("\n", snippet.shader_features)).AppendLine();
                        sb.AppendLine();
                    }
                    if (snippet.multi_compiles != null && snippet.multi_compiles.Length > 0)
                    {
                        sb.AppendFormat("Keywords always included into build:\n\n{0}", String.Join("\n", snippet.multi_compiles)).AppendLine();
                        sb.AppendLine();
                    }
                    if (snippet.builtins != null && snippet.builtins.Length > 0)
                    {
                        sb.AppendFormat("Builtin keywords used:\n\n{0}", String.Join("\n", snippet.builtins)).AppendLine();
                        sb.AppendLine();
                    }
                    sb.AppendLine();

                    if (snippet.variants != null && snippet.variants.Count > 0)
                    {
                        sb.AppendFormat("{0} keyword variants used in scene:", snippet.variants.Count).AppendLine();
                        sb.AppendLine();
                        for (int j = 0; j < snippet.variants.Count; ++j)
                        {
                            sb.AppendFormat("[{0}]:", j).AppendLine();
                            sb.Append(String.Join("\n", snippet.variants[j].ToArray()));
                            sb.AppendLine();
                            sb.AppendLine();
                        }
                    }
                    else
                    {
                        sb.Append(TAG_NO_KEYWORDS_DEFINED).AppendLine();
                    }
                    sb.AppendLine();
                }
                result = sb.ToString();
            }
            else
            {
                result = "Empty ShaderParsedCombinations.";
            }
            Debug.Log(result);
            return(result);
        }