public static bool ParseShader(FxcShader shader) { ShaderBytecode ByteCodeObj; ShaderProfile ShaderProfile; try { ByteCodeObj = new ShaderBytecode(shader.ByteCode); ShaderProfile = ByteCodeObj.GetVersion(); switch (ShaderProfile.Version) { case ShaderVersion.VertexShader: case ShaderVersion.PixelShader: case ShaderVersion.GeometryShader: //VersionMajor = br.ReadByte();//4,5 //appears to be shader model version //VersionMinor = br.ReadByte(); //perhaps shader minor version break; default: shader.VersionMajor = (byte)ShaderProfile.Major; shader.VersionMinor = (byte)ShaderProfile.Minor; break; } shader.Disassembly = ByteCodeObj.Disassemble(); } catch (Exception ex) { shader.LastError += ex.ToString() + "\r\n"; return(false); } return(true); }
public string Export() { var sb = new StringBuilder(); if (m_Keywords.Length > 0) { sb.Append("Keywords { "); foreach (string keyword in m_Keywords) { sb.Append($"\"{keyword}\" "); } sb.Append("}\n"); } sb.Append("\"\n"); if (m_ProgramCode.Length > 0) { switch (m_ProgramType) { case ShaderGpuProgramType.kShaderGpuProgramGLLegacy: case ShaderGpuProgramType.kShaderGpuProgramGLES31AEP: case ShaderGpuProgramType.kShaderGpuProgramGLES31: case ShaderGpuProgramType.kShaderGpuProgramGLES3: case ShaderGpuProgramType.kShaderGpuProgramGLES: case ShaderGpuProgramType.kShaderGpuProgramGLCore32: case ShaderGpuProgramType.kShaderGpuProgramGLCore41: case ShaderGpuProgramType.kShaderGpuProgramGLCore43: sb.Append(Encoding.UTF8.GetString(m_ProgramCode)); break; case ShaderGpuProgramType.kShaderGpuProgramDX9VertexSM20: case ShaderGpuProgramType.kShaderGpuProgramDX9VertexSM30: case ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM20: case ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM30: { var shaderBytecode = new ShaderBytecode(m_ProgramCode); sb.Append(shaderBytecode.Disassemble()); break; } case ShaderGpuProgramType.kShaderGpuProgramDX10Level9Vertex: case ShaderGpuProgramType.kShaderGpuProgramDX10Level9Pixel: case ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM40: case ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM50: case ShaderGpuProgramType.kShaderGpuProgramDX11PixelSM40: case ShaderGpuProgramType.kShaderGpuProgramDX11PixelSM50: case ShaderGpuProgramType.kShaderGpuProgramDX11GeometrySM40: case ShaderGpuProgramType.kShaderGpuProgramDX11GeometrySM50: case ShaderGpuProgramType.kShaderGpuProgramDX11HullSM50: case ShaderGpuProgramType.kShaderGpuProgramDX11DomainSM50: { int start = 6; if (magic == 201509030) // 5.3 { start = 5; } var buff = new byte[m_ProgramCode.Length - start]; Buffer.BlockCopy(m_ProgramCode, start, buff, 0, buff.Length); var shaderBytecode = new ShaderBytecode(buff); sb.Append(shaderBytecode.Disassemble()); break; } case ShaderGpuProgramType.kShaderGpuProgramMetalVS: case ShaderGpuProgramType.kShaderGpuProgramMetalFS: using (var reader = new BinaryReader(new MemoryStream(m_ProgramCode))) { var fourCC = reader.ReadUInt32(); if (fourCC == 0xf00dcafe) { int offset = reader.ReadInt32(); reader.BaseStream.Position = offset; } var entryName = reader.ReadStringToNull(); var buff = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); sb.Append(Encoding.UTF8.GetString(buff)); } break; default: sb.Append($"/*Unsupported program data {m_ProgramType}*/"); break; } } sb.Append('"'); return(sb.ToString()); }
public bool Read(BinaryReader br, bool exbyteflag) { Name = FxcFile.ReadString(br); if (Name.Length == 0) { Name = FxcFile.ReadString(br); //why (seems to be GS only) exbyteflag = true; } Params = FxcFile.ReadStringArray(br); byte bufferCount = br.ReadByte(); var buffers = new List <FxcShaderBufferRef>(); for (int e = 0; e < bufferCount; e++) { FxcShaderBufferRef ext = new FxcShaderBufferRef(); ext.Name = FxcFile.ReadString(br); ext.Unk0Ushort = br.ReadUInt16(); buffers.Add(ext); } Buffers = buffers.ToArray(); byte exbyte = 0; if (exbyteflag) { exbyte = br.ReadByte(); //not sure what this is used for... if ((exbyte != 0)) { } } uint datalength = br.ReadUInt32(); if (datalength > 0) { uint magic_dxbc = br.ReadUInt32(); if (magic_dxbc != 1128421444) //"DXBC" - directx bytecode header { LastError += "Unexpected data found at DXBC header...\r\n"; return(false); //didn't find the DXBC header... abort! } br.BaseStream.Position -= 4; //wind back because dx needs that header ByteCode = br.ReadBytes((int)datalength); try { ByteCodeObj = new ShaderBytecode(ByteCode); ShaderProfile = ByteCodeObj.GetVersion(); Disassembly = ByteCodeObj.Disassemble(); switch (ShaderProfile.Version) { case ShaderVersion.VertexShader: case ShaderVersion.PixelShader: case ShaderVersion.GeometryShader: VersionMajor = br.ReadByte(); //4,5 //appears to be shader model version VersionMinor = br.ReadByte(); //perhaps shader minor version break; default: VersionMajor = (byte)ShaderProfile.Major; VersionMinor = (byte)ShaderProfile.Minor; break; } } catch (Exception ex) { LastError += ex.ToString() + "\r\n"; return(false); } } else { } return(true); }
public static bool ValidateShaderOfType(string Type, string HlslType, string OriginalFile, string SourcePath) { var metadata = new ShaderMetadata(OriginalFile.Replace(".bin", ".txt")); // Grab the technique along with each #define used var techniqueId = metadata.GetTechnique(); var macros = GetCompilationMacros(Type, HlslType, metadata.GetDefines().ToList()); //Program.LogLine("Validating shader [Technique: {0:X8}]: {1}...", techniqueId, OriginalFile); // Read from disk, compile, then disassemble to text ShaderBytecode originalBytecode = null; ShaderBytecode newBytecode = null; try { originalBytecode = RecompileShader3DMigoto(OriginalFile, HlslType).Strip(m_StripFlags); //originalBytecode = ShaderBytecode.FromFile(OriginalFile).Strip(m_StripFlags); newBytecode = CompileShaderOfType(SourcePath, HlslType, macros).Strip(m_StripFlags); } catch (InvalidProgramException e) { Program.Log($"{OriginalFile}\n{e.Message}"); return(false); } string[] originalDisasm = originalBytecode.Disassemble(DisassemblyFlags.None).Split('\n'); string[] newDisasm = newBytecode.Disassemble(DisassemblyFlags.None).Split('\n'); // Sometimes the newly generated output will be shorter than the original code. Add some padding // to prevent out-of-bounds array access. if (originalDisasm.Length > newDisasm.Length) { string[] newArray = new string[originalDisasm.Length]; for (int i = 0; i < newArray.Length; i++) { newArray[i] = "\n"; } newDisasm.CopyTo(newArray, 0); newDisasm = newArray; } try { ValidateShaderHeader(originalDisasm, newDisasm); ValidateShaderCode(originalDisasm, newDisasm); } catch (Exception) { //Program.LogLine("Validation failed."); // Dump raw disassembly to file File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-old.txt", originalDisasm); File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-new.txt", newDisasm); // // Generate the "symbolic" diff by: // // - Replacing all temporary registers with rX.xxxx // - Sorting all lines // - Eliminating all empty lines // var tempRegisterExpr = new Regex(@"r\d\.[xXyYzZwW]{1,4}", RegexOptions.Compiled); for (int i = 0; i < originalDisasm.Length; i++) { originalDisasm[i] = tempRegisterExpr.Replace(originalDisasm[i], "rX.xxxx"); newDisasm[i] = tempRegisterExpr.Replace(newDisasm[i], "rX.xxxx"); } File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-symbolic-old.txt", originalDisasm.Where(x => !string.IsNullOrWhiteSpace(x)).OrderBy(x => x)); File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-symbolic-new.txt", newDisasm.Where(x => !string.IsNullOrWhiteSpace(x)).OrderBy(x => x)); return(false); } return(true); }