From 4cc6c996510445205e29883a60c4f699f8c88c23 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Mon, 11 Aug 2025 21:21:34 +0800 Subject: [PATCH 1/8] fix about --- Assets/CompilerShaderTools/Editor/MaliCompilerInstaller.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Assets/CompilerShaderTools/Editor/MaliCompilerInstaller.cs b/Assets/CompilerShaderTools/Editor/MaliCompilerInstaller.cs index fc615cb..2bb7d05 100644 --- a/Assets/CompilerShaderTools/Editor/MaliCompilerInstaller.cs +++ b/Assets/CompilerShaderTools/Editor/MaliCompilerInstaller.cs @@ -193,8 +193,7 @@ public static void ShowAbout() EditorUtility.DisplayDialog("关于Mali Compiler Integration", "Mali Compiler Integration for Unity\n" + "版本: 1.0\n" + - "作者: MiniMax Agent\n" + - "更新时间: 2025-08-05\n\n" + + "更新时间: 2025-08-11\n\n" + "专业级Unity Shader性能分析工具,集成ARM Mali Offline Compiler," + "提供详细的性能指标分析和智能优化建议。\n\n" + "支持Mali-G71到Mali-G715等多种GPU型号," + From da3aae1cdb604eb7363962b293ac21804ec68027 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Tue, 12 Aug 2025 20:04:29 +0800 Subject: [PATCH 2/8] Are there alternative approaches? OpenCompiledShader calls methods in the Unity engine and opens the generated shader code by default; are there alternative approaches? --- .../Editor/UnityShaderCompiler.cs | 12 ++++++++++++ Assets/MaliCompilerReports.meta | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) delete mode 100644 Assets/MaliCompilerReports.meta diff --git a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs index 7ce9119..48e4afc 100644 --- a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs +++ b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs @@ -100,6 +100,18 @@ private static string CompileShaderForSpecificPlatform(Shader shader, ShaderComp } // 反射调用OpenCompiledShader方法 + /// + /// OpenCompiledShader 会调用Unity引擎内的方法, + /// 在生成shader代码之后默认会额外打开它 + /// 是否有其他方式呢? + /// + /// + /// + /// + /// + /// + /// + /// public static bool InvokeOpenCompiledShader( Shader shader, int mode, diff --git a/Assets/MaliCompilerReports.meta b/Assets/MaliCompilerReports.meta deleted file mode 100644 index 4f560ab..0000000 --- a/Assets/MaliCompilerReports.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 07ceaafe7f7bb824bb709c743529a207 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 8544a978bb016dd0c3438bbc6e993ac18bfb5d32 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Tue, 19 Aug 2025 22:22:23 +0800 Subject: [PATCH 3/8] Some minor fixes --- .../Editor/MaliCompilerWindow.cs | 25 ++++++++-- .../Editor/UnityShaderCompiler.cs | 46 ++++++++++++++++++- README.md | 4 +- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs index db70ab3..ef466ee 100644 --- a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs +++ b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs @@ -76,6 +76,9 @@ public static void QuickCompile() private List optimizationSuggestions; private string analysisReport = ""; + // 滚动位置 + private Vector2 analysisScrollPosition; + // 折叠面板状态 private bool showConfiguration = true; private bool showShaderSelection = true; @@ -97,6 +100,10 @@ private void OnEnable() private void InitializeStyles() { + // 确保EditorStyles已经初始化 + if (EditorStyles.boldLabel == null) + return; + headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 16, @@ -389,7 +396,12 @@ private void DrawResultsSection() if (showAnalysis && !string.IsNullOrEmpty(analysisReport)) { EditorGUILayout.BeginVertical(sectionStyle); - EditorGUILayout.TextArea(analysisReport, EditorStyles.wordWrappedLabel, GUILayout.Height(200)); + + // 使用类成员变量保存滚动位置 + analysisScrollPosition = EditorGUILayout.BeginScrollView(analysisScrollPosition, GUILayout.Height(200)); + GUILayout.TextArea(analysisReport, EditorStyles.wordWrappedLabel); + EditorGUILayout.EndScrollView(); + EditorGUILayout.EndVertical(); } } @@ -498,7 +510,14 @@ private ShaderCompileResult CompileShader() statusMessage = "正在解析Shader文件..."; try - { + { + // 检查是否为URP着色器 + bool isURPShader = UnityShaderCompiler.IsURPShader(selectedShader); + if (isURPShader) + { + statusMessage = "检测到URP着色器,使用特殊处理..."; + } + var result = UnityShaderCompiler.CompileShaderForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); if (result.vertexShader == null || result.fragmentShader == null) @@ -598,7 +617,7 @@ private string CompileShaderFile(string filePath, string shaderType) if (config.enableVerboseOutput) { - startInfo.Arguments += " -v"; + startInfo.Arguments += " -d"; } using (var process = Process.Start(startInfo)) diff --git a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs index 48e4afc..e56f9a0 100644 --- a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs +++ b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs @@ -5,6 +5,7 @@ using System.Text; using System.Reflection; using System; +using System.Text.RegularExpressions; using UnityEditor.Rendering; /// @@ -48,6 +49,11 @@ public static ShaderCompileResult CompileShaderForPlatform(Shader shader, Shader { result.vertexShader = ExtractVertexShaderFromCompiled(compiledShader); result.fragmentShader = ExtractFragmentShaderFromCompiled(compiledShader); + + // 处理GLSL版本问题,将#version 300 es替换为#version 310 es + result.vertexShader = ProcessGLSLVersion(result.vertexShader); + result.fragmentShader = ProcessGLSLVersion(result.fragmentShader); + result.isSuccess = true; } else @@ -64,6 +70,17 @@ public static ShaderCompileResult CompileShaderForPlatform(Shader shader, Shader return result; } + /// + /// 处理GLSL版本,将#version 300 es替换为#version 310 es以解决某些编译问题 + /// + private static string ProcessGLSLVersion(string shaderCode) + { + if (string.IsNullOrEmpty(shaderCode)) + return shaderCode; + + // 使用正则表达式替换#version 300 es为#version 310 es + return Regex.Replace(shaderCode, @"#version\s+300\s+es", "#version 310 es"); + } /// /// 使用反射调用Unity内部API进行Shader编译 @@ -299,4 +316,31 @@ public static bool IsValidForMaliAnalysis(string shaderCode) shaderCode.Contains("varying") || shaderCode.Contains("attribute"); } -} + + /// + /// 检测是否为URP着色器 + /// + public static bool IsURPShader(Shader shader) + { + if (shader == null) + return false; + + string shaderPath = AssetDatabase.GetAssetPath(shader); + if (string.IsNullOrEmpty(shaderPath)) + return false; + + // 检查shader文件内容是否包含URP特征 + try + { + string shaderContent = File.ReadAllText(shaderPath); + return shaderContent.Contains("Universal Render Pipeline") || + shaderContent.Contains("UniversalPipeline") || + shaderContent.Contains("URP") || + shaderContent.Contains("Packages/com.unity.render-pipelines.universal"); + } + catch + { + return false; + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 856d295..f66af43 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unity Mali Compiler 集成工具使用指南 -**版本:1.0** -**更新时间:2025-08-05** +**版本:1.1** +**更新时间:2025-08-19** ## 📋 概述 From 56125352daece979cbfa59a2a05adfab8b873e71 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Tue, 19 Aug 2025 22:23:59 +0800 Subject: [PATCH 4/8] Version 1.1.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f66af43..ed0cbde 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Unity Mali Compiler 集成工具使用指南 -**版本:1.1** +**版本:1.1.0** **更新时间:2025-08-19** ## 📋 概述 From f45507fda7229bb15659a8f29aca36a6add21c65 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Thu, 28 Aug 2025 10:41:38 +0800 Subject: [PATCH 5/8] Fix the issue with multiple variants of the shader --- .../Editor/MaliCompilerWindow.cs | 80 ++++++++++++- .../Editor/UnityShaderCompiler.cs | 109 +++++++++++++++++- 2 files changed, 186 insertions(+), 3 deletions(-) diff --git a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs index ef466ee..0b207b6 100644 --- a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs +++ b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs @@ -63,6 +63,10 @@ public static void QuickCompile() // Unity编译后代码输入 private static string unityCompiledVertexCode = ""; private static string unityCompiledFragmentCode = ""; + + // 变体缓存与选择 + private List compiledVariants = new List(); + private int selectedVariantIndex = 0; // 编译状态 private bool isCompiling = false; @@ -96,6 +100,9 @@ private void OnEnable() if (selectedGPUIndex < 0) selectedGPUIndex = 4; InitializeStyles(); + + compiledVariants = new List(); + selectedVariantIndex = 0; } private void InitializeStyles() @@ -223,6 +230,32 @@ private void DrawShaderSelectionSection() selectedGPUIndex = EditorGUILayout.Popup("GPU型号", selectedGPUIndex, gpuModels); config.selectedGPUModel = gpuModels[selectedGPUIndex]; } + + // 变体选择 + EditorGUILayout.Space(5); + EditorGUILayout.LabelField("变体:", EditorStyles.boldLabel); + EditorGUILayout.BeginHorizontal(); + bool hasVariants = compiledVariants != null && compiledVariants.Count > 0; + GUI.enabled = hasVariants; + int maxIndex = Mathf.Max(0, (hasVariants ? compiledVariants.Count - 1 : 0)); + int newIndex = EditorGUILayout.IntSlider("变体索引", selectedVariantIndex, 0, maxIndex); + if (newIndex != selectedVariantIndex) + { + selectedVariantIndex = newIndex; + if (hasVariants) + { + selectedVariantIndex = Mathf.Clamp(selectedVariantIndex, 0, compiledVariants.Count - 1); + unityCompiledVertexCode = compiledVariants[selectedVariantIndex].vertexShader; + unityCompiledFragmentCode = compiledVariants[selectedVariantIndex].fragmentShader; + } + } + GUI.enabled = true; + if (GUILayout.Button("刷新变体", GUILayout.Width(90))) + { + RefreshVariants(); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.LabelField($"当前变体数: {(hasVariants ? compiledVariants.Count : 0)}", EditorStyles.miniLabel); } else { @@ -501,6 +534,31 @@ private void HandleDragAndDrop() } } + private void RefreshVariants() + { + if (selectedShader == null) + { + compiledVariants = new List(); + selectedVariantIndex = 0; + unityCompiledVertexCode = ""; + unityCompiledFragmentCode = ""; + return; + } + + compiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + selectedVariantIndex = Mathf.Clamp(selectedVariantIndex, 0, Mathf.Max(0, compiledVariants.Count - 1)); + if (compiledVariants.Count > 0) + { + unityCompiledVertexCode = compiledVariants[selectedVariantIndex].vertexShader; + unityCompiledFragmentCode = compiledVariants[selectedVariantIndex].fragmentShader; + } + else + { + unityCompiledVertexCode = ""; + unityCompiledFragmentCode = ""; + } + } + private ShaderCompileResult CompileShader() { if (selectedShader == null) @@ -518,7 +576,27 @@ private ShaderCompileResult CompileShader() statusMessage = "检测到URP着色器,使用特殊处理..."; } - var result = UnityShaderCompiler.CompileShaderForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + // 准备变体 + if (compiledVariants == null || compiledVariants.Count == 0) + { + compiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + } + if (compiledVariants == null || compiledVariants.Count == 0) + { + statusMessage = "无法解析任何变体,请检查Shader或平台选择"; + return new ShaderCompileResult(); + } + + selectedVariantIndex = Mathf.Clamp(selectedVariantIndex, 0, compiledVariants.Count - 1); + var chosenVariant = compiledVariants[selectedVariantIndex]; + + var result = new ShaderCompileResult + { + vertexShader = chosenVariant.vertexShader, + fragmentShader = chosenVariant.fragmentShader, + isSuccess = true, + platform = UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x + }; if (result.vertexShader == null || result.fragmentShader == null) { diff --git a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs index e56f9a0..66b8448 100644 --- a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs +++ b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs @@ -92,7 +92,7 @@ private static string CompileShaderForSpecificPlatform(Shader shader, ShaderComp // 模拟Shader Inspector中"Compile and show code"的典型参数 int mode = 3; // 模式:Custom int platformMask = 1 << (int)platform; // 目标平台掩码(Windows) - bool includeAllVariants = false; // 不包含所有变体 + bool includeAllVariants = true; // 包含所有变体 bool preprocessOnly = false; // 不仅预处理 bool stripLineDirectives = false; // 不剥离行指令 @@ -343,4 +343,109 @@ public static bool IsURPShader(Shader shader) return false; } } -} \ No newline at end of file + + /// + /// 表示一个已编译的 Shader 变体(按Pass/Keyword组合聚合) + /// + public class ShaderCompiledVariant + { + public string vertexShader; + public string fragmentShader; + public string passName = ""; + public string keywords = ""; + } + + /// + /// 获取所有变体的已编译代码(按顺序配对第N个Vertex与第N个Fragment) + /// + public static List CompileAllVariantsForPlatform(Shader shader, ShaderCompilerPlatform platform) + { + var variants = new List(); + if (shader == null) return variants; + + string compiled = CompileShaderForSpecificPlatform(shader, platform); + if (string.IsNullOrEmpty(compiled)) return variants; + + var vertexList = ExtractAllShaderSections(compiled, "#ifdef VERTEX", "#endif"); + var fragmentList = ExtractAllShaderSections(compiled, "#ifdef FRAGMENT", "#endif"); + + int count = Math.Min(vertexList.Count, fragmentList.Count); + for (int i = 0; i < count; i++) + { + variants.Add(new ShaderCompiledVariant + { + vertexShader = ProcessGLSLVersion(vertexList[i]), + fragmentShader = ProcessGLSLVersion(fragmentList[i]), + passName = "", + keywords = "" + }); + } + return variants; + } + + /// + /// 提取所有匹配的区间,并移除最外层标签 + /// + private static List ExtractAllShaderSections(string code, string startMarker, string endMarker) + { + var results = new List(); + if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(startMarker) || string.IsNullOrEmpty(endMarker)) + return results; + + var lines = code.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); + var buffer = new List(); + var stack = new Stack(); + bool inSection = false; + + foreach (var line in lines) + { + string trimmed = line.Trim(); + if (!inSection && trimmed == startMarker) + { + inSection = true; + stack.Push(startMarker); + buffer.Clear(); + // 开始记录,但不包含起始标签 + continue; + } + + if (inSection) + { + if (trimmed.StartsWith("#if") || trimmed.StartsWith("#ifdef") || trimmed.StartsWith("#ifndef")) + { + stack.Push(trimmed); + buffer.Add(line); + } + else if (trimmed == endMarker) + { + if (stack.Count > 0) stack.Pop(); + + if (stack.Count == 0) + { + // 结束当前段,保存 + inSection = false; + // 去掉前后空行 + var sb = new StringBuilder(); + for (int i = 0; i < buffer.Count; i++) + { + if (!string.IsNullOrWhiteSpace(buffer[i])) + sb.AppendLine(buffer[i]); + } + results.Add(sb.ToString().TrimEnd('\r', '\n')); + buffer.Clear(); + } + else + { + buffer.Add(line); + } + } + else + { + buffer.Add(line); + } + } + } + + return results; + } +} From 24a38349072ad09444052138b7c49dace13752e5 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Thu, 28 Aug 2025 11:10:22 +0800 Subject: [PATCH 6/8] Fix the issue of incorrect name display for the shader's multiple passes and add a filtering function --- .../Editor/MaliCompilerWindow.cs | 83 ++++-- .../Editor/UnityShaderCompiler.cs | 241 ++++++++++++++---- 2 files changed, 256 insertions(+), 68 deletions(-) diff --git a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs index 0b207b6..d3ef9a7 100644 --- a/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs +++ b/Assets/CompilerShaderTools/Editor/MaliCompilerWindow.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System; using System.Text; +using System.Linq; using static UnityShaderCompiler; /// @@ -65,8 +66,11 @@ public static void QuickCompile() private static string unityCompiledFragmentCode = ""; // 变体缓存与选择 + private List allCompiledVariants = new List(); private List compiledVariants = new List(); private int selectedVariantIndex = 0; + private string passFilter = ""; + private string keywordFilter = ""; // 编译状态 private bool isCompiling = false; @@ -101,8 +105,11 @@ private void OnEnable() InitializeStyles(); + allCompiledVariants = new List(); compiledVariants = new List(); selectedVariantIndex = 0; + passFilter = ""; + keywordFilter = ""; } private void InitializeStyles() @@ -231,31 +238,48 @@ private void DrawShaderSelectionSection() config.selectedGPUModel = gpuModels[selectedGPUIndex]; } + // 筛选 + EditorGUILayout.Space(5); + EditorGUILayout.LabelField("变体筛选:", EditorStyles.boldLabel); + passFilter = EditorGUILayout.TextField("Pass 名称包含", passFilter); + keywordFilter = EditorGUILayout.TextField("关键词包含", keywordFilter); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("应用筛选", GUILayout.Width(80))) + { + ApplyVariantFilter(); + } + if (GUILayout.Button("清空筛选", GUILayout.Width(80))) + { + passFilter = ""; + keywordFilter = ""; + ApplyVariantFilter(); + } + if (GUILayout.Button("刷新变体", GUILayout.Width(90))) + { + RefreshVariants(); + } + EditorGUILayout.EndHorizontal(); + // 变体选择 EditorGUILayout.Space(5); EditorGUILayout.LabelField("变体:", EditorStyles.boldLabel); - EditorGUILayout.BeginHorizontal(); bool hasVariants = compiledVariants != null && compiledVariants.Count > 0; - GUI.enabled = hasVariants; int maxIndex = Mathf.Max(0, (hasVariants ? compiledVariants.Count - 1 : 0)); int newIndex = EditorGUILayout.IntSlider("变体索引", selectedVariantIndex, 0, maxIndex); if (newIndex != selectedVariantIndex) { selectedVariantIndex = newIndex; - if (hasVariants) - { - selectedVariantIndex = Mathf.Clamp(selectedVariantIndex, 0, compiledVariants.Count - 1); - unityCompiledVertexCode = compiledVariants[selectedVariantIndex].vertexShader; - unityCompiledFragmentCode = compiledVariants[selectedVariantIndex].fragmentShader; - } + UpdateCompiledCodeFromSelected(); } - GUI.enabled = true; - if (GUILayout.Button("刷新变体", GUILayout.Width(90))) + EditorGUILayout.LabelField($"当前变体数: {(hasVariants ? compiledVariants.Count : 0)} / 全量: {allCompiledVariants.Count}", EditorStyles.miniLabel); + + // 当前变体元数据展示 + if (hasVariants && selectedVariantIndex >= 0 && selectedVariantIndex < compiledVariants.Count) { - RefreshVariants(); + var v = compiledVariants[selectedVariantIndex]; + EditorGUILayout.LabelField("当前 Pass 名称:", string.IsNullOrEmpty(v.passName) ? "(未命名)" : v.passName); + EditorGUILayout.LabelField("当前 Keywords:", string.IsNullOrEmpty(v.keywords) ? "(无)" : v.keywords); } - EditorGUILayout.EndHorizontal(); - EditorGUILayout.LabelField($"当前变体数: {(hasVariants ? compiledVariants.Count : 0)}", EditorStyles.miniLabel); } else { @@ -538,6 +562,7 @@ private void RefreshVariants() { if (selectedShader == null) { + allCompiledVariants = new List(); compiledVariants = new List(); selectedVariantIndex = 0; unityCompiledVertexCode = ""; @@ -545,9 +570,32 @@ private void RefreshVariants() return; } - compiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + allCompiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + ApplyVariantFilter(); + } + + private void ApplyVariantFilter() + { + if (allCompiledVariants == null) allCompiledVariants = new List(); + IEnumerable q = allCompiledVariants; + + if (!string.IsNullOrEmpty(passFilter)) + { + q = q.Where(v => !string.IsNullOrEmpty(v.passName) && v.passName.IndexOf(passFilter, StringComparison.OrdinalIgnoreCase) >= 0); + } + if (!string.IsNullOrEmpty(keywordFilter)) + { + q = q.Where(v => !string.IsNullOrEmpty(v.keywords) && v.keywords.IndexOf(keywordFilter, StringComparison.OrdinalIgnoreCase) >= 0); + } + + compiledVariants = q.ToList(); selectedVariantIndex = Mathf.Clamp(selectedVariantIndex, 0, Mathf.Max(0, compiledVariants.Count - 1)); - if (compiledVariants.Count > 0) + UpdateCompiledCodeFromSelected(); + } + + private void UpdateCompiledCodeFromSelected() + { + if (compiledVariants != null && compiledVariants.Count > 0 && selectedVariantIndex >= 0 && selectedVariantIndex < compiledVariants.Count) { unityCompiledVertexCode = compiledVariants[selectedVariantIndex].vertexShader; unityCompiledFragmentCode = compiledVariants[selectedVariantIndex].fragmentShader; @@ -579,11 +627,12 @@ private ShaderCompileResult CompileShader() // 准备变体 if (compiledVariants == null || compiledVariants.Count == 0) { - compiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + allCompiledVariants = UnityShaderCompiler.CompileAllVariantsForPlatform(selectedShader, UnityEditor.Rendering.ShaderCompilerPlatform.GLES3x); + ApplyVariantFilter(); } if (compiledVariants == null || compiledVariants.Count == 0) { - statusMessage = "无法解析任何变体,请检查Shader或平台选择"; + statusMessage = "无法解析任何变体,请检查Shader或平台选择/筛选条件"; return new ShaderCompileResult(); } diff --git a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs index 66b8448..8367f05 100644 --- a/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs +++ b/Assets/CompilerShaderTools/Editor/UnityShaderCompiler.cs @@ -356,7 +356,7 @@ public class ShaderCompiledVariant } /// - /// 获取所有变体的已编译代码(按顺序配对第N个Vertex与第N个Fragment) + /// 获取所有变体(顺序扫描,按 Pass 名称与 Keywords 就地绑定,再配对 VS/FS) /// public static List CompileAllVariantsForPlatform(Shader shader, ShaderCompilerPlatform platform) { @@ -366,86 +366,225 @@ public static List CompileAllVariantsForPlatform(Shader s string compiled = CompileShaderForSpecificPlatform(shader, platform); if (string.IsNullOrEmpty(compiled)) return variants; - var vertexList = ExtractAllShaderSections(compiled, "#ifdef VERTEX", "#endif"); - var fragmentList = ExtractAllShaderSections(compiled, "#ifdef FRAGMENT", "#endif"); + // 顺序扫描状态 + string currentPassName = ""; + string currentKeywords = ""; + string currentLocalKeywords = ""; - int count = Math.Min(vertexList.Count, fragmentList.Count); - for (int i = 0; i < count; i++) + // 暂存分段:按 (passName, keywords) 分组的 VS/FS 列表 + var vertexBuckets = new Dictionary>(); + var fragmentBuckets = new Dictionary>(); + + string[] lines = compiled.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.None); + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + + // 1) 进入/识别 Pass 名称(支持多种格式) + // Pass { Name "World" ... } + var mPassNameInline = Regex.Match(line, @"^\s*Pass\s*\{\s*Name\s*""([^""]+)""", RegexOptions.IgnoreCase); + if (mPassNameInline.Success) + { + currentPassName = mPassNameInline.Groups[1].Value.Trim(); + continue; + } + // 独立 Name "World" + var mName = Regex.Match(line, @"^\s*Name\s*""([^""]+)""", RegexOptions.IgnoreCase); + if (mName.Success) + { + currentPassName = mName.Groups[1].Value.Trim(); + continue; + } + // 兼容其它格式:Pass: SomeName + var mPassColon = Regex.Match(line, @"^\s*Pass\s*:\s*'?([^'\r\n]+)'?\s*$", RegexOptions.IgnoreCase); + if (mPassColon.Success) + { + currentPassName = mPassColon.Groups[1].Value.Trim(); + continue; + } + // 兼容:Subshader x, pass y 'Name' + var mSubPass = Regex.Match(line, @"Subshader\s+\d+.*pass\s+\d+(?:\s*'([^']+)')?", RegexOptions.IgnoreCase); + if (mSubPass.Success && mSubPass.Groups.Count > 1 && mSubPass.Groups[1].Success) + { + currentPassName = mSubPass.Groups[1].Value.Trim(); + continue; + } + + // 2) 关键词元数据(每遇到新块会覆盖) + var mKw = Regex.Match(line, @"^\s*Keywords\s*:\s*(.+)$", RegexOptions.IgnoreCase); + if (mKw.Success) + { + currentKeywords = mKw.Groups[1].Value.Trim(); + continue; + } + var mLocalKw = Regex.Match(line, @"^\s*Local\s+Keywords\s*:\s*(.+)$", RegexOptions.IgnoreCase); + if (mLocalKw.Success) + { + currentLocalKeywords = mLocalKw.Groups[1].Value.Trim(); + continue; + } + + // 3) 采集 VS/FS 段 + if (line.Trim() == "#ifdef VERTEX") + { + string code = CollectShaderSection(lines, ref i, "#ifdef VERTEX", "#endif"); + string key = ComposeBucketKey(currentPassName, currentKeywords, currentLocalKeywords); + if (!vertexBuckets.TryGetValue(key, out var list)) { list = new List(); vertexBuckets[key] = list; } + list.Add(ProcessGLSLVersion(code)); + continue; + } + if (line.Trim() == "#ifdef FRAGMENT") + { + string code = CollectShaderSection(lines, ref i, "#ifdef FRAGMENT", "#endif"); + string key = ComposeBucketKey(currentPassName, currentKeywords, currentLocalKeywords); + if (!fragmentBuckets.TryGetValue(key, out var list)) { list = new List(); fragmentBuckets[key] = list; } + list.Add(ProcessGLSLVersion(code)); + continue; + } + } + + // 4) 将同组 VS/FS 配对组装为变体 + foreach (var kv in vertexBuckets) { - variants.Add(new ShaderCompiledVariant + string key = kv.Key; + fragmentBuckets.TryGetValue(key, out var fsList); + var vsList = kv.Value; + int cnt = Math.Min(vsList.Count, (fsList != null ? fsList.Count : 0)); + if (cnt <= 0) continue; + + DecomposeBucketKey(key, out string passName, out string combinedKeywords); + for (int i = 0; i < cnt; i++) { - vertexShader = ProcessGLSLVersion(vertexList[i]), - fragmentShader = ProcessGLSLVersion(fragmentList[i]), - passName = "", - keywords = "" - }); + variants.Add(new ShaderCompiledVariant + { + vertexShader = vsList[i], + fragmentShader = fsList[i], + passName = passName, + keywords = combinedKeywords + }); + } } + return variants; + + // 工具:采集以 #ifdef 开始的完整段(不含外层 #ifdef/#endif) + static string CollectShaderSection(string[] allLines, ref int index, string start, string end) + { + var sb = new StringBuilder(); + int depth = 0; + // 当前行是 start,不包含在结果中 + for (int i = index + 1; i < allLines.Length; i++) + { + string l = allLines[i].Trim(); + if (l.StartsWith("#if") || l.StartsWith("#ifdef") || l.StartsWith("#ifndef")) + { + depth++; + sb.AppendLine(allLines[i]); + continue; + } + if (l == end) + { + if (depth == 0) + { + index = i; // 将外层 #endif 消费掉 + break; + } + else + { + depth--; + sb.AppendLine(allLines[i]); + continue; + } + } + sb.AppendLine(allLines[i]); + } + return sb.ToString().TrimEnd('\r', '\n'); + } + + // 工具:组合/拆解桶键 + static string ComposeBucketKey(string pass, string kw, string localKw) + { + string p = string.IsNullOrEmpty(pass) ? "(unnamed)" : pass.Trim(); + string k1 = string.IsNullOrEmpty(kw) ? "" : kw.Trim(); + string k2 = string.IsNullOrEmpty(localKw) ? "" : localKw.Trim(); + string k = string.IsNullOrEmpty(k1) ? k2 : (string.IsNullOrEmpty(k2) ? k1 : (k1 + " " + k2)); + return p + "||" + k; // 简单分隔 + } + + static void DecomposeBucketKey(string key, out string pass, out string keywords) + { + int pos = key.IndexOf("||", StringComparison.Ordinal); + if (pos >= 0) + { + pass = key.Substring(0, pos); + keywords = key.Substring(pos + 2); + } + else + { + pass = key; + keywords = ""; + } + } } /// /// 提取所有匹配的区间,并移除最外层标签 /// + // 保留:不再使用 ExtractAllShaderSections,但留作后续可能用途 private static List ExtractAllShaderSections(string code, string startMarker, string endMarker) { var results = new List(); if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(startMarker) || string.IsNullOrEmpty(endMarker)) return results; - - var lines = code.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); - var buffer = new List(); - var stack = new Stack(); - bool inSection = false; - - foreach (var line in lines) + var lines = code.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.None); + int i = 0; + while (i < lines.Length) { - string trimmed = line.Trim(); - if (!inSection && trimmed == startMarker) + if (lines[i].Trim() == startMarker) { - inSection = true; - stack.Push(startMarker); - buffer.Clear(); - // 开始记录,但不包含起始标签 - continue; + string section = ""; + int idx = i; + section = CollectSection(lines, ref idx, startMarker, endMarker); + if (!string.IsNullOrWhiteSpace(section)) results.Add(section); + i = idx + 1; } + else + { + i++; + } + } + return results; - if (inSection) + static string CollectSection(string[] allLines, ref int index, string start, string end) + { + var sb = new StringBuilder(); + int depth = 0; + for (int i = index + 1; i < allLines.Length; i++) { - if (trimmed.StartsWith("#if") || trimmed.StartsWith("#ifdef") || trimmed.StartsWith("#ifndef")) + string l = allLines[i].Trim(); + if (l.StartsWith("#if") || l.StartsWith("#ifdef") || l.StartsWith("#ifndef")) { - stack.Push(trimmed); - buffer.Add(line); + depth++; + sb.AppendLine(allLines[i]); + continue; } - else if (trimmed == endMarker) + if (l == end) { - if (stack.Count > 0) stack.Pop(); - - if (stack.Count == 0) + if (depth == 0) { - // 结束当前段,保存 - inSection = false; - // 去掉前后空行 - var sb = new StringBuilder(); - for (int i = 0; i < buffer.Count; i++) - { - if (!string.IsNullOrWhiteSpace(buffer[i])) - sb.AppendLine(buffer[i]); - } - results.Add(sb.ToString().TrimEnd('\r', '\n')); - buffer.Clear(); + index = i; + break; } else { - buffer.Add(line); + depth--; + sb.AppendLine(allLines[i]); + continue; } } - else - { - buffer.Add(line); - } + sb.AppendLine(allLines[i]); } + return sb.ToString().TrimEnd('\r', '\n'); } - - return results; } } From 4f401bee432d6d3e08c76aadca2e73269f88e186 Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Thu, 28 Aug 2025 11:13:38 +0800 Subject: [PATCH 7/8] Version 1.2.0 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed0cbde..63ac45b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unity Mali Compiler 集成工具使用指南 -**版本:1.1.0** -**更新时间:2025-08-19** +**版本:1.2.0** +**更新时间:2025-08-28** ## 📋 概述 From c8844b939c09d780ef72e4b6467abfaa7431d6ad Mon Sep 17 00:00:00 2001 From: arcsearoc Date: Fri, 12 Sep 2025 10:08:44 +0800 Subject: [PATCH 8/8] add README_CN.md --- README.md | 308 ++++++++++++++++++++++++++------------------------- README_CN.md | 272 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 427 insertions(+), 153 deletions(-) create mode 100644 README_CN.md diff --git a/README.md b/README.md index 63ac45b..f17e117 100644 --- a/README.md +++ b/README.md @@ -1,270 +1,272 @@ -# Unity Mali Compiler 集成工具使用指南 +# Unity Mali Compiler Integration Tool User Guide -**版本:1.2.0** -**更新时间:2025-08-28** +**[中文](README_CN.md) | English** -## 📋 概述 +**Version: 1.2.0** +**Updated: 2025-08-28** -Unity Mali Compiler集成工具是一个专业级的Unity编辑器扩展,允许开发者直接在Unity中调用ARM Mali Offline Compiler来分析Shader性能,获得详细的性能指标和优化建议。 +## 📋 Overview -### 🎯 主要功能 +Unity Mali Compiler Integration Tool is a professional Unity Editor extension that allows developers to directly invoke ARM Mali Offline Compiler within Unity to analyze Shader performance, providing detailed performance metrics and optimization recommendations. -- **一键Shader分析** - 直接在Unity中编译和分析Shader -- **智能代码解析** - 自动将Unity Shader转换为Mali Compiler可处理的GLSL格式 -- **详细性能报告** - 提供工作寄存器、指令周期、瓶颈分析等关键指标 -- **智能优化建议** - 基于编译结果自动生成优化建议 -- **多GPU支持** - 支持Mali-G71到Mali-G715等多种GPU型号 -- **批量处理** - 支持保存结果、自动报告生成等 +### 🎯 Key Features -## 🚀 快速开始 +- **One-Click Shader Analysis** - Compile and analyze Shaders directly in Unity +- **Smart Code Parsing** - Automatically convert Unity Shaders to GLSL format for Mali Compiler +- **Detailed Performance Reports** - Provide key metrics including work registers, instruction cycles, bottleneck analysis +- **Intelligent Optimization Suggestions** - Automatically generate optimization recommendations based on compilation results +- **Multi-GPU Support** - Support various GPU models from Mali-G71 to Mali-G715 +- **Batch Processing** - Support result saving, automatic report generation, etc. -### 1. 环境准备 +## 🚀 Quick Start -#### 下载Mali Offline Compiler(工程也内置了一份) +### 1. Environment Setup -1. 访问ARM官网:https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio/components/mali-offline-compiler -2. 根据你的操作系统下载对应版本 -3. 安装完成后记录`malioc.exe`的路径 +#### Download Mali Offline Compiler (Also included in the project) -#### 安装Unity工具 +1. Visit ARM official website: https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio/components/mali-offline-compiler +2. Download the version corresponding to your operating system +3. After installation, record the path to `malioc.exe` -1. 将工具包中的所有`.cs`文件复制到Unity项目的`Editor`文件夹中 -2. 等待Unity编译完成 -3. 在菜单栏找到`Tools > Mali Compiler Integration` +#### Install Unity Tool -### 2. 工具配置 +1. Copy all `.cs` files from the tool package to the `Editor` folder in your Unity project +2. Wait for Unity to complete compilation +3. Find `Tools > Mali Compiler Integration` in the menu bar -#### 基础配置 +### 2. Tool Configuration -1. 打开`Tools > Mali Compiler Integration > Main Window` -2. 在"配置设置"中点击"浏览"按钮 -3. 选择Mali Offline Compiler的`malioc.exe`文件 -4. 配置验证成功后即可使用 +#### Basic Configuration -#### 高级配置(可选) +1. Open `Tools > Mali Compiler Integration > Main Window` +2. Click the "Browse" button in "Configuration Settings" +3. Select the `malioc.exe` file of Mali Offline Compiler +4. Ready to use after successful configuration verification -- **详细输出**:启用后获得更详细的编译信息 -- **保存临时文件**:用于调试,保存中间转换的GLSL文件 -- **自动保存结果**:自动保存分析报告到本地 -- **显示优化建议**:开启智能优化建议功能 +#### Advanced Configuration (Optional) -### 3. 使用流程 +- **Verbose Output**: Enable for more detailed compilation information +- **Save Temporary Files**: For debugging, save intermediate converted GLSL files +- **Auto Save Results**: Automatically save analysis reports locally +- **Show Optimization Suggestions**: Enable intelligent optimization suggestion feature -#### 方法一:主窗口分析 +### 3. Usage Workflow -1. 打开Mali Compiler主窗口 -2. 选择要分析的Shader文件 -3. (可选)指定特定的GPU型号 -4. 点击"🚀 开始分析" -5. 查看性能分析报告和优化建议 +#### Method 1: Main Window Analysis -#### 方法二:快速分析 +1. Open Mali Compiler main window +2. Select the Shader file to analyze +3. (Optional) Specify a particular GPU model +4. Click "🚀 Start Analysis" +5. View performance analysis report and optimization suggestions -1. 在Project窗口中选择Shader文件 -2. 右键选择`Tools > Mali Compiler Integration > Quick Compile` -3. 或使用菜单栏`Tools > Mali Compiler Integration > Quick Compile` +#### Method 2: Quick Analysis -#### 方法三:拖拽分析 +1. Select Shader file in Project window +2. Right-click and select `Tools > Mali Compiler Integration > Quick Compile` +3. Or use menu bar `Tools > Mali Compiler Integration > Quick Compile` -1. 打开Mali Compiler窗口 -2. 直接将Shader文件拖拽到窗口中 -3. 自动开始分析流程 +#### Method 3: Drag & Drop Analysis -## 📊 结果解读 +1. Open Mali Compiler window +2. Directly drag Shader file into the window +3. Automatically start analysis process -### 性能指标说明 +## 📊 Result Interpretation -#### 工作寄存器(Work Registers) +### Performance Metrics Explanation -- **含义**:Shader执行时使用的寄存器数量 -- **优化目标**:越低越好(建议≤32) -- **影响**:数量过高会限制并行执行的线程数 +#### Work Registers -#### Uniform寄存器(Uniform Registers) +- **Meaning**: Number of registers used during Shader execution +- **Optimization Goal**: Lower is better (recommended ≤32) +- **Impact**: Excessive numbers limit the number of threads that can execute in parallel -- **含义**:存储常量数据的只读寄存器 -- **特点**:在所有线程间共享,影响相对较小 +#### Uniform Registers -#### 16位运算占比(16-bit Arithmetic) +- **Meaning**: Read-only registers storing constant data +- **Characteristics**: Shared among all threads, relatively minor impact -- **含义**:使用16位精度运算的百分比 -- **优化目标**:越高越好(建议≥50%) -- **影响**:16位运算比32位运算快一倍 +#### 16-bit Arithmetic Ratio -#### 指令周期(Instruction Cycles) +- **Meaning**: Percentage of 16-bit precision operations used +- **Optimization Goal**: Higher is better (recommended ≥50%) +- **Impact**: 16-bit operations are twice as fast as 32-bit operations -- **总周期数**:所有指令的累积周期 -- **最短路径**:最优化执行路径的周期数 -- **最长路径**:最复杂执行路径的周期数 +#### Instruction Cycles -#### 瓶颈单元(Bound Unit) +- **Total Cycles**: Cumulative cycles of all instructions +- **Shortest Path**: Cycles for optimized execution path +- **Longest Path**: Cycles for most complex execution path -- **A (Arithmetic)**:算术运算瓶颈 -- **T (Texture)**:纹理采样瓶颈 -- **LS (Load/Store)**:内存读写瓶颈 -- **V (Varying)**:插值计算瓶颈 +#### Bound Unit -### Shader属性分析 +- **A (Arithmetic)**: Arithmetic operation bottleneck +- **T (Texture)**: Texture sampling bottleneck +- **LS (Load/Store)**: Memory read/write bottleneck +- **V (Varying)**: Interpolation calculation bottleneck -#### 性能影响属性 +### Shader Property Analysis -- **Has uniform computation**:包含统一计算,建议移至CPU -- **Uses late ZS test**:使用延迟深度测试,影响Early-Z优化 -- **Has side-effects**:具有副作用,影响并行执行 -- **Stack spilling**:寄存器溢出,严重性能问题 +#### Performance Impact Properties -## 🔧 优化建议指南 +- **Has uniform computation**: Contains uniform computation, recommend moving to CPU +- **Uses late ZS test**: Uses late depth testing, affects Early-Z optimization +- **Has side-effects**: Has side effects, affects parallel execution +- **Stack spilling**: Register overflow, serious performance issue -### 优先级颜色说明 +## 🔧 Optimization Guide -- 🔴 **严重**:必须立即处理的性能问题 -- 🟠 **高**:显著影响性能,建议优先优化 -- 🟡 **中**:有一定影响,可适当优化 -- 🟢 **低**:轻微影响,时间充裕时优化 +### Priority Color Coding -### 常见优化策略 +- 🔴 **Critical**: Performance issues that must be addressed immediately +- 🟠 **High**: Significantly affects performance, recommend priority optimization +- 🟡 **Medium**: Some impact, moderate optimization recommended +- 🟢 **Low**: Minor impact, optimize when time permits -#### 1. 寄存器优化 +### Common Optimization Strategies + +#### 1. Register Optimization ```hlsl -// ❌ 避免:过多局部变量 +// ❌ Avoid: Too many local variables float temp1 = calcA(); float temp2 = calcB(); float temp3 = calcC(); float result = temp1 * temp2 + temp3; -// ✅ 推荐:合并计算 +// ✅ Recommended: Merge calculations float result = calcA() * calcB() + calcC(); ``` -#### 2. 精度优化 +#### 2. Precision Optimization ```hlsl -// ❌ 避免:不必要的高精度 +// ❌ Avoid: Unnecessary high precision float4 color = tex2D(_MainTex, uv); float brightness = dot(color.rgb, float3(0.299, 0.587, 0.114)); -// ✅ 推荐:使用适当精度 +// ✅ Recommended: Use appropriate precision half4 color = tex2D(_MainTex, uv); half brightness = dot(color.rgb, half3(0.299, 0.587, 0.114)); ``` -#### 3. 分支优化 +#### 3. Branch Optimization ```hlsl -// ❌ 避免:复杂分支 +// ❌ Avoid: Complex branches if (condition1) { if (condition2) { - // 复杂计算 + // Complex calculation } } -// ✅ 推荐:使用lerp或step +// ✅ Recommended: Use lerp or step float factor = step(0.5, condition1) * step(0.5, condition2); result = lerp(defaultValue, complexValue, factor); ``` -#### 4. 纹理优化 +#### 4. Texture Optimization ```hlsl -// ❌ 避免:过多纹理采样 +// ❌ Avoid: Too many texture samples float4 tex1 = tex2D(_Tex1, uv); float4 tex2 = tex2D(_Tex2, uv); float4 tex3 = tex2D(_Tex3, uv); float4 tex4 = tex2D(_Tex4, uv); -// ✅ 推荐:纹理合并或减少采样 +// ✅ Recommended: Texture packing or reduced sampling float4 packedTex = tex2D(_PackedTex, uv); float4 tex1 = packedTex.rrra; float4 tex2 = packedTex.ggga; ``` -## 🎮 GPU型号对比 +## 🎮 GPU Model Comparison -### Bifrost架构 (Mali-G71, G72, G76) +### Bifrost Architecture (Mali-G71, G72, G76) -- **特点**:传统的分离式处理单元 -- **优化重点**:算术运算优化 -- **显示信息**:Arithmetic单元统计 +- **Characteristics**: Traditional separate processing units +- **Optimization Focus**: Arithmetic operation optimization +- **Display Info**: Arithmetic unit statistics -### Valhall架构 (Mali-G77, G78, G310, G510, G610, G710, G715) +### Valhall Architecture (Mali-G77, G78, G310, G510, G610, G710, G715) -- **特点**:并行处理引擎,更细分的单元统计 -- **优化重点**:FMA、CVT、SFU单元平衡 -- **显示信息**:详细的单元分解 +- **Characteristics**: Parallel processing engine with more detailed unit statistics +- **Optimization Focus**: Balance FMA, CVT, SFU units +- **Display Info**: Detailed unit breakdown -## 🔍 故障排除 +## 🔍 Troubleshooting -### 常见问题 +### Common Issues -#### 1. "Mali Compiler文件不存在" +#### 1. "Mali Compiler file does not exist" -- **原因**:malioc.exe路径配置错误 -- **解决**:重新下载并安装Mali Offline Compiler,确认路径正确 +- **Cause**: Incorrect malioc.exe path configuration +- **Solution**: Re-download and install Mali Offline Compiler, confirm correct path -#### 2. "无法解析Shader文件" +#### 2. "Cannot parse Shader file" -- **原因**:不支持的Shader格式或复杂的Surface Shader -- **解决**:使用标准的Unity Shader格式,避免过于复杂的宏定义 +- **Cause**: Unsupported Shader format or complex Surface Shader +- **Solution**: Use standard Unity Shader format, avoid overly complex macro definitions -#### 3. "编译失败" +#### 3. "Compilation failed" -- **原因**:HLSL到GLSL转换出错 -- **解决**:检查Shader语法,避免使用不支持的函数 +- **Cause**: HLSL to GLSL conversion error +- **Solution**: Check Shader syntax, avoid using unsupported functions -#### 4. Stack Spilling警告 +#### 4. Stack Spilling Warning -- **原因**:寄存器使用过多 -- **解决**:减少局部变量,降低精度,简化计算逻辑 +- **Cause**: Excessive register usage +- **Solution**: Reduce local variables, lower precision, simplify calculation logic -### 调试技巧 +### Debugging Tips -1. **启用详细输出**:在高级选项中开启详细输出模式 -2. **保存临时文件**:查看转换后的GLSL代码,定位转换问题 -3. **逐步简化**:从简单Shader开始,逐步增加复杂度 +1. **Enable Verbose Output**: Turn on verbose output mode in advanced options +2. **Save Temporary Files**: View converted GLSL code to locate conversion issues +3. **Gradual Simplification**: Start with simple Shaders, gradually increase complexity -## 📈 性能基准 +## 📈 Performance Benchmarks -### 推荐性能目标 +### Recommended Performance Targets -| 指标 | 移动设备目标 | 高端设备目标 | -| ------- | ------ | ------ | -| 工作寄存器 | ≤16 | ≤32 | -| 16位运算占比 | ≥60% | ≥40% | -| 纹理采样数 | ≤2 | ≤4 | -| 最长路径周期 | ≤50 | ≤100 | +| Metric | Mobile Target | High-end Target | +| ----------------------- | ------------- | --------------- | +| Work Registers | ≤16 | ≤32 | +| 16-bit Arithmetic Ratio | ≥60% | ≥40% | +| Texture Samples | ≤2 | ≤4 | +| Longest Path Cycles | ≤50 | ≤100 | -### GPU性能层级 +### GPU Performance Tiers -| GPU型号 | 性能层级 | 适用场景 | -| ------------- | ---- | --------- | -| Mali-G71/G72 | 入门级 | 简单游戏,基础效果 | -| Mali-G76/G77 | 中端 | 中等复杂度游戏 | -| Mali-G78/G310 | 中高端 | 复杂游戏,丰富效果 | -| Mali-G510+ | 高端 | 顶级游戏,高级效果 | +| GPU Model | Performance Tier | Use Case | +| ------------- | ---------------- | -------------------------------- | +| Mali-G71/G72 | Entry-level | Simple games, basic effects | +| Mali-G76/G77 | Mid-range | Medium complexity games | +| Mali-G78/G310 | Mid-high-end | Complex games, rich effects | +| Mali-G510+ | High-end | Top-tier games, advanced effects | -## 📚 扩展资源 +## 📚 Extended Resources -### ARM官方文档 +### ARM Official Documentation -- [Mali GPU架构指南](https://developer.arm.com/documentation/102849/latest/) -- [Mali Offline Compiler用户指南](https://developer.arm.com/documentation/101863/latest/) -- [Mali GPU最佳实践](https://developer.arm.com/documentation/101897/latest/) +- [Mali GPU Architecture Guide](https://developer.arm.com/documentation/102849/latest/) +- [Mali Offline Compiler User Guide](https://developer.arm.com/documentation/101863/latest/) +- [Mali GPU Best Practices](https://developer.arm.com/documentation/101897/latest/) -### Unity优化资源 +### Unity Optimization Resources -- [Unity Shader优化指南](https://docs.unity3d.com/Manual/SL-ShaderPerformance.html) -- [移动平台图形优化](https://docs.unity3d.com/Manual/MobileOptimisation.html) +- [Unity Shader Optimization Guide](https://docs.unity3d.com/Manual/SL-ShaderPerformance.html) +- [Mobile Graphics Optimization](https://docs.unity3d.com/Manual/MobileOptimisation.html) -## 🤝 技术支持 +## 🤝 Technical Support -如果在使用过程中遇到问题,建议: +If you encounter issues during use, we recommend: -1. 查看Unity Console中的详细错误信息 -2. 启用"详细输出"模式获取更多信息 -3. 检查Mali Offline Compiler版本兼容性 -4. 确认Shader格式符合工具要求 +1. Check detailed error information in Unity Console +2. Enable "Verbose Output" mode for more information +3. Check Mali Offline Compiler version compatibility +4. Ensure Shader format meets tool requirements --- -**注意**:本工具基于ARM Mali Offline Compiler,需要有效的Mali Compiler安装才能正常工作。工具会自动处理大部分HLSL到GLSL的转换,但复杂的Shader可能需要手动调整。 +**Note**: This tool is based on ARM Mali Offline Compiler and requires a valid Mali Compiler installation to work properly. The tool automatically handles most HLSL to GLSL conversions, but complex Shaders may require manual adjustments. diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..2ad9557 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,272 @@ +# Unity Mali Compiler 集成工具使用指南 + +**中文 | [English](README.md)** + +**版本:1.2.0** +**更新时间:2025-08-28** + +## 📋 概述 + +Unity Mali Compiler集成工具是一个专业级的Unity编辑器扩展,允许开发者直接在Unity中调用ARM Mali Offline Compiler来分析Shader性能,获得详细的性能指标和优化建议。 + +### 🎯 主要功能 + +- **一键Shader分析** - 直接在Unity中编译和分析Shader +- **智能代码解析** - 自动将Unity Shader转换为Mali Compiler可处理的GLSL格式 +- **详细性能报告** - 提供工作寄存器、指令周期、瓶颈分析等关键指标 +- **智能优化建议** - 基于编译结果自动生成优化建议 +- **多GPU支持** - 支持Mali-G71到Mali-G715等多种GPU型号 +- **批量处理** - 支持保存结果、自动报告生成等 + +## 🚀 快速开始 + +### 1. 环境准备 + +#### 下载Mali Offline Compiler(工程也内置了一份) + +1. 访问ARM官网:https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio/components/mali-offline-compiler +2. 根据你的操作系统下载对应版本 +3. 安装完成后记录`malioc.exe`的路径 + +#### 安装Unity工具 + +1. 将工具包中的所有`.cs`文件复制到Unity项目的`Editor`文件夹中 +2. 等待Unity编译完成 +3. 在菜单栏找到`Tools > Mali Compiler Integration` + +### 2. 工具配置 + +#### 基础配置 + +1. 打开`Tools > Mali Compiler Integration > Main Window` +2. 在"配置设置"中点击"浏览"按钮 +3. 选择Mali Offline Compiler的`malioc.exe`文件 +4. 配置验证成功后即可使用 + +#### 高级配置(可选) + +- **详细输出**:启用后获得更详细的编译信息 +- **保存临时文件**:用于调试,保存中间转换的GLSL文件 +- **自动保存结果**:自动保存分析报告到本地 +- **显示优化建议**:开启智能优化建议功能 + +### 3. 使用流程 + +#### 方法一:主窗口分析 + +1. 打开Mali Compiler主窗口 +2. 选择要分析的Shader文件 +3. (可选)指定特定的GPU型号 +4. 点击"🚀 开始分析" +5. 查看性能分析报告和优化建议 + +#### 方法二:快速分析 + +1. 在Project窗口中选择Shader文件 +2. 右键选择`Tools > Mali Compiler Integration > Quick Compile` +3. 或使用菜单栏`Tools > Mali Compiler Integration > Quick Compile` + +#### 方法三:拖拽分析 + +1. 打开Mali Compiler窗口 +2. 直接将Shader文件拖拽到窗口中 +3. 自动开始分析流程 + +## 📊 结果解读 + +### 性能指标说明 + +#### 工作寄存器(Work Registers) + +- **含义**:Shader执行时使用的寄存器数量 +- **优化目标**:越低越好(建议≤32) +- **影响**:数量过高会限制并行执行的线程数 + +#### Uniform寄存器(Uniform Registers) + +- **含义**:存储常量数据的只读寄存器 +- **特点**:在所有线程间共享,影响相对较小 + +#### 16位运算占比(16-bit Arithmetic) + +- **含义**:使用16位精度运算的百分比 +- **优化目标**:越高越好(建议≥50%) +- **影响**:16位运算比32位运算快一倍 + +#### 指令周期(Instruction Cycles) + +- **总周期数**:所有指令的累积周期 +- **最短路径**:最优化执行路径的周期数 +- **最长路径**:最复杂执行路径的周期数 + +#### 瓶颈单元(Bound Unit) + +- **A (Arithmetic)**:算术运算瓶颈 +- **T (Texture)**:纹理采样瓶颈 +- **LS (Load/Store)**:内存读写瓶颈 +- **V (Varying)**:插值计算瓶颈 + +### Shader属性分析 + +#### 性能影响属性 + +- **Has uniform computation**:包含统一计算,建议移至CPU +- **Uses late ZS test**:使用延迟深度测试,影响Early-Z优化 +- **Has side-effects**:具有副作用,影响并行执行 +- **Stack spilling**:寄存器溢出,严重性能问题 + +## 🔧 优化建议指南 + +### 优先级颜色说明 + +- 🔴 **严重**:必须立即处理的性能问题 +- 🟠 **高**:显著影响性能,建议优先优化 +- 🟡 **中**:有一定影响,可适当优化 +- 🟢 **低**:轻微影响,时间充裕时优化 + +### 常见优化策略 + +#### 1. 寄存器优化 + +```hlsl +// ❌ 避免:过多局部变量 +float temp1 = calcA(); +float temp2 = calcB(); +float temp3 = calcC(); +float result = temp1 * temp2 + temp3; + +// ✅ 推荐:合并计算 +float result = calcA() * calcB() + calcC(); +``` + +#### 2. 精度优化 + +```hlsl +// ❌ 避免:不必要的高精度 +float4 color = tex2D(_MainTex, uv); +float brightness = dot(color.rgb, float3(0.299, 0.587, 0.114)); + +// ✅ 推荐:使用适当精度 +half4 color = tex2D(_MainTex, uv); +half brightness = dot(color.rgb, half3(0.299, 0.587, 0.114)); +``` + +#### 3. 分支优化 + +```hlsl +// ❌ 避免:复杂分支 +if (condition1) { + if (condition2) { + // 复杂计算 + } +} + +// ✅ 推荐:使用lerp或step +float factor = step(0.5, condition1) * step(0.5, condition2); +result = lerp(defaultValue, complexValue, factor); +``` + +#### 4. 纹理优化 + +```hlsl +// ❌ 避免:过多纹理采样 +float4 tex1 = tex2D(_Tex1, uv); +float4 tex2 = tex2D(_Tex2, uv); +float4 tex3 = tex2D(_Tex3, uv); +float4 tex4 = tex2D(_Tex4, uv); + +// ✅ 推荐:纹理合并或减少采样 +float4 packedTex = tex2D(_PackedTex, uv); +float4 tex1 = packedTex.rrra; +float4 tex2 = packedTex.ggga; +``` + +## 🎮 GPU型号对比 + +### Bifrost架构 (Mali-G71, G72, G76) + +- **特点**:传统的分离式处理单元 +- **优化重点**:算术运算优化 +- **显示信息**:Arithmetic单元统计 + +### Valhall架构 (Mali-G77, G78, G310, G510, G610, G710, G715) + +- **特点**:并行处理引擎,更细分的单元统计 +- **优化重点**:FMA、CVT、SFU单元平衡 +- **显示信息**:详细的单元分解 + +## 🔍 故障排除 + +### 常见问题 + +#### 1. "Mali Compiler文件不存在" + +- **原因**:malioc.exe路径配置错误 +- **解决**:重新下载并安装Mali Offline Compiler,确认路径正确 + +#### 2. "无法解析Shader文件" + +- **原因**:不支持的Shader格式或复杂的Surface Shader +- **解决**:使用标准的Unity Shader格式,避免过于复杂的宏定义 + +#### 3. "编译失败" + +- **原因**:HLSL到GLSL转换出错 +- **解决**:检查Shader语法,避免使用不支持的函数 + +#### 4. Stack Spilling警告 + +- **原因**:寄存器使用过多 +- **解决**:减少局部变量,降低精度,简化计算逻辑 + +### 调试技巧 + +1. **启用详细输出**:在高级选项中开启详细输出模式 +2. **保存临时文件**:查看转换后的GLSL代码,定位转换问题 +3. **逐步简化**:从简单Shader开始,逐步增加复杂度 + +## 📈 性能基准 + +### 推荐性能目标 + +| 指标 | 移动设备目标 | 高端设备目标 | +| ------- | ------ | ------ | +| 工作寄存器 | ≤16 | ≤32 | +| 16位运算占比 | ≥60% | ≥40% | +| 纹理采样数 | ≤2 | ≤4 | +| 最长路径周期 | ≤50 | ≤100 | + +### GPU性能层级 + +| GPU型号 | 性能层级 | 适用场景 | +| ------------- | ---- | --------- | +| Mali-G71/G72 | 入门级 | 简单游戏,基础效果 | +| Mali-G76/G77 | 中端 | 中等复杂度游戏 | +| Mali-G78/G310 | 中高端 | 复杂游戏,丰富效果 | +| Mali-G510+ | 高端 | 顶级游戏,高级效果 | + +## 📚 扩展资源 + +### ARM官方文档 + +- [Mali GPU架构指南](https://developer.arm.com/documentation/102849/latest/) +- [Mali Offline Compiler用户指南](https://developer.arm.com/documentation/101863/latest/) +- [Mali GPU最佳实践](https://developer.arm.com/documentation/101897/latest/) + +### Unity优化资源 + +- [Unity Shader优化指南](https://docs.unity3d.com/Manual/SL-ShaderPerformance.html) +- [移动平台图形优化](https://docs.unity3d.com/Manual/MobileOptimisation.html) + +## 🤝 技术支持 + +如果在使用过程中遇到问题,建议: + +1. 查看Unity Console中的详细错误信息 +2. 启用"详细输出"模式获取更多信息 +3. 检查Mali Offline Compiler版本兼容性 +4. 确认Shader格式符合工具要求 + +--- + +**注意**:本工具基于ARM Mali Offline Compiler,需要有效的Mali Compiler安装才能正常工作。工具会自动处理大部分HLSL到GLSL的转换,但复杂的Shader可能需要手动调整。