public static DebugConstantDeclaration Parse(DebugBytecodeReader reader, DebugBytecodeReader decReader) { var result = new DebugConstantDeclaration(); var nameOffset = decReader.ReadUInt32("NameOffset"); result.RegisterSet = decReader.ReadEnum16 <RegisterSet>("RegisterSet"); result.RegisterIndex = decReader.ReadUInt16("RegisterIndex"); result.RegisterCount = decReader.ReadUInt16("RegisterCount"); decReader.ReadUInt16("Reserved"); var typeInfoOffset = decReader.ReadUInt32("TypeInfoOffset"); var defaultValueOffset = decReader.ReadUInt32("DefaultValueOffset"); var nameReader = reader.CopyAtOffset("NameReader", decReader, (int)nameOffset); result.Name = nameReader.ReadString("Name"); var typeReader = reader.CopyAtOffset("TypeReader", decReader, (int)typeInfoOffset); result.Type = DebugConstantType.Parse(reader, typeReader); if (defaultValueOffset != 0) { //Note: thre are corrisponding def instructions. TODO: check that they are the same var defaultValueReader = reader.CopyAtOffset("DefaultValueReader", decReader, (int)defaultValueOffset); var elementCount = result.Type.GetSize() / 4; for (int i = 0; i < elementCount; i++) { result.DefaultValue.Add(defaultValueReader.ReadSingle($"DefaultValue {i}")); } } return(result); }
public static DebugConstantType Parse(DebugBytecodeReader reader, DebugBytecodeReader typeReader) { var result = new DebugConstantType(); result.ParameterClass = typeReader.ReadEnum16 <ParameterClass>("ParameterClass"); result.ParameterType = typeReader.ReadEnum16 <ParameterType>("ParameterType"); result.Rows = typeReader.ReadUInt16("Rows"); result.Columns = typeReader.ReadUInt16("Columns"); result.Elements = typeReader.ReadUInt16("Elements"); result.MemberCount = typeReader.ReadUInt16("Members"); var memberInfoOffset = typeReader.ReadUInt32("MemberInfoOffset"); if (memberInfoOffset != 0) { var memberInfoReader = reader.CopyAtOffset("MemberReader", typeReader, (int)memberInfoOffset); for (int i = 0; i < result.MemberCount; i++) { var nameOffset = memberInfoReader.ReadUInt32($"Member{i}NameOffset"); var nameReader = reader.CopyAtOffset($"Member{i}NameReader", memberInfoReader, (int)nameOffset); nameReader.ReadString("Name"); var typeOffset = memberInfoReader.ReadUInt32($"Member{i}TypeOffset"); var memberTypeReader = reader.CopyAtOffset($"Member{i}TypeReader", memberInfoReader, (int)typeOffset); result.Members.Add(DebugConstantType.Parse(reader, memberTypeReader)); } } return(result); }
public static DebugLoopRegisterMapping Parse(DebugBytecodeReader reader) { var result = new DebugLoopRegisterMapping(); result.Buffer = reader.ReadUInt16("Buffer"); result.SourceReg = reader.ReadUInt16("SourceReg"); result.Component = reader.ReadUInt16("Component"); result.TargetReg = reader.ReadUInt16("TargetReg"); return(result); }
public static DebugMSInfo Parse(DebugBytecodeReader reader) { return(new DebugMSInfo() { GroupSharedBytesUsed = reader.ReadUInt32("GroupSharedBytesUsed"), GroupSharedBytesDependentOnViewID = reader.ReadUInt32("GroupSharedBytesDependentOnViewID"), PayloadSizeInBytes = reader.ReadUInt32("PayloadSizeInBytes"), MaxOutputVertices = reader.ReadUInt16("MaxOutputVertices"), MaxOutputPrimitives = reader.ReadUInt16("MaxOutputPrimitives"), }); }
public static DebugClassType Parse(DebugBytecodeReader reader, DebugBytecodeReader classTypeReader) { var nameOffset = classTypeReader.ReadUInt32("nameOffset"); var nameReader = reader.CopyAtOffset("nameReader", classTypeReader, (int)nameOffset); return(new DebugClassType { Name = nameReader.ReadString("Name"), ID = classTypeReader.ReadUInt16("ID"), ConstantBufferStride = classTypeReader.ReadUInt16("ConstantBufferStride"), Texture = classTypeReader.ReadUInt16("Texture"), Sampler = classTypeReader.ReadUInt16("Sampler") }); }
public static DebugDebugNameChunk Parse(DebugBytecodeReader reader, uint chunkSize) { var result = new DebugDebugNameChunk(); var flags = reader.ReadUInt16("Flags"); //Currently unused var nameLength = reader.ReadUInt16("NameLength"); result.Name = reader.ReadString("Name"); var padding = 4 - (nameLength + 1) % 4; //Aligned to 4 byte boundary if (padding > 0) { reader.ReadBytes("Padding", padding); } return(result); }
public static DebugConstantBufferMapping Parse(DebugBytecodeReader reader) { var result = new DebugConstantBufferMapping(); result.Buffer = reader.ReadUInt16("Buffer"); result.StartReg = reader.ReadUInt16("StartReg"); result.RegCount = reader.ReadUInt16("RegCount"); result.TargetReg = reader.ReadUInt16("TargetReg"); for (int i = 0; i < 4; i++) { var type = reader.ReadEnum8 <DataConversionType>("DataConversionType"); result.DataConversion[i] = type; } return(result); }
public static DebugRuntimeConstantMapping Parse(DebugBytecodeReader reader) { var result = new DebugRuntimeConstantMapping(); result.ConstantDescription = reader.ReadEnum16 <RuntimeConstantDescription>("ConstantDescription"); result.TargetReg = reader.ReadUInt16("TargetReg"); return(result); }
public static DebugClassInstance Parse(DebugBytecodeReader reader, DebugBytecodeReader classInstanceReader) { var nameOffset = classInstanceReader.ReadUInt32("NameOffset"); var nameReader = reader.CopyAtOffset("nameReader", classInstanceReader, (int)nameOffset); var name = nameReader.ReadString("nameReader"); var type = classInstanceReader.ReadUInt16("type"); var unknown = classInstanceReader.ReadUInt16("ClassInstanceUnknown"); return(new DebugClassInstance { Name = name, Type = type, ConstantBuffer = classInstanceReader.ReadUInt16("ConstantBuffer"), ConstantBufferOffset = classInstanceReader.ReadUInt16("ConstantBufferOffset"), Texture = classInstanceReader.ReadUInt16("Texture"), Sampler = classInstanceReader.ReadUInt16("Sampler") }); }
public static DebugShaderType Parse(DebugBytecodeReader reader, DebugBytecodeReader typeReader, DebugShaderVersion target, int indent, bool isFirst, uint parentOffset) { var result = new DebugShaderType(indent, isFirst) { VariableClass = typeReader.ReadEnum16 <ShaderVariableClass>("VariableClass"), VariableType = typeReader.ReadEnum16 <ShaderVariableType>("VariableType"), Rows = typeReader.ReadUInt16("Rows"), Columns = typeReader.ReadUInt16("Columns"), ElementCount = typeReader.ReadUInt16("ElementCount") }; var memberCount = typeReader.ReadUInt16("memberCount"); var memberOffset = typeReader.ReadUInt32("memberOffset"); if (target.MajorVersion >= 5) { var subTypeOffset = typeReader.ReadInt32("subTypeOffset"); // Guessing if (subTypeOffset != 0) { var parentInterfaceReader = reader.CopyAtOffset("subtypeReader", typeReader, (int)subTypeOffset); result.SubType = DebugShaderType.Parse(reader, parentInterfaceReader, target, indent + 4, true, parentOffset); } var baseClassOffset = typeReader.ReadUInt32("baseClassOffset"); if (baseClassOffset != 0) { var baseClassReader = reader.CopyAtOffset("baseClassReader", typeReader, (int)baseClassOffset); result.BaseClass = DebugShaderType.Parse(reader, baseClassReader, target, indent + 4, true, parentOffset); } result.NumberOfInterfaces = typeReader.ReadUInt32("NumberOfInterfaces"); var interfaceSectionOffset = typeReader.ReadUInt32("InterfaceSectionOffset"); if (interfaceSectionOffset != 0) { var interfaceSectionReader = reader.CopyAtOffset("interfaceSectionReader", typeReader, (int)interfaceSectionOffset); for (int i = 0; i < result.NumberOfInterfaces; i++) { var interfaceTypeOffset = interfaceSectionReader.ReadUInt32($"UnkInterface{i}"); var interfaceReader = reader.CopyAtOffset($"InterfaceReader {i}", typeReader, (int)interfaceTypeOffset); result.Interfaces.Add(DebugShaderType.Parse(reader, interfaceReader, target, indent + 4, i == 0, parentOffset)); } } var parentNameOffset = typeReader.ReadUInt32("parentNameOffset"); if (parentNameOffset > 0) { var parentNameReader = reader.CopyAtOffset("parentNameOffset", typeReader, (int)parentNameOffset); result.BaseTypeName = parentNameReader.ReadString("BaseTypeName"); } } if (memberCount > 0) { var memberReader = reader.CopyAtOffset("memberReader", typeReader, (int)memberOffset); for (int i = 0; i < memberCount; i++) { memberReader.AddIndent($"Member {i}"); result.Members.Add(DebugShaderTypeMember.Parse(reader, memberReader, target, indent + 4, i == 0, parentOffset)); memberReader.RemoveIndent(); } } if (target.ProgramType == ProgramType.LibraryShader && target.MajorVersion == 4) { var unk1 = typeReader.ReadUInt32("Unk1"); var unk2 = typeReader.ReadUInt32("Unk2"); var unk3 = typeReader.ReadUInt32("Unk3"); var unk4 = typeReader.ReadUInt32("Unk4"); var typeNameOffset = typeReader.ReadUInt32("typeNameoffset"); var typeNameReader = reader.CopyAtOffset("TypeNameReader", typeReader, (int)typeNameOffset); typeNameReader.ReadString("TypeName"); Debug.Assert(unk1 == 0, $"ShaderType.Unk1={unk1}"); Debug.Assert(unk2 == 0, $"ShaderType.Unk2={unk2}"); Debug.Assert(unk3 == 0, $"ShaderType.Unk3={unk3}"); Debug.Assert(unk4 == 0, $"ShaderType.Unk4={unk4}"); } return(result); }
static void Main(string[] args) { args = new string[] { "-O", "test.html", "-h", @"C:\Files\KM\ShaderStudio\src\UnityTests\bin\Debug\Blob\outer_wilds\Assets\Shader\SpritesDefault\VS_BF58DDF502C51FEB5145F1D0310B4327.o" }; var options = new Options(); for (int i = 0; i < args.Length; i++) { switch (args[i]) { case "-O": if (args.Length <= i + 1) { Console.Error.WriteLine("No output path specified"); return; } options.DestPath = args[i + 1]; i += 1; break; case "-a": options.Mode = DecompileMode.Dissassemble; break; case "-d": options.Mode = DecompileMode.Debug; break; case "-h": options.Mode = DecompileMode.DebugHtml; break; default: options.SourcePath = args[i]; break; } } if (string.IsNullOrEmpty(options.SourcePath)) { Console.Error.WriteLine("No source path specified"); Environment.Exit(1); } byte[] data = null; try { data = File.ReadAllBytes(options.SourcePath); } catch (Exception ex) { Console.Error.WriteLine("Error reading source"); Console.Error.WriteLine(ex); Environment.Exit(1); } var programType = GetProgramType(data); using (var sw = GetStream(options)) { if (programType == ProgramType.Unknown) { Console.Error.WriteLine($"Unable to identify shader object format"); Environment.Exit(1); } else if (programType == ProgramType.DXBC) { if (options.Mode == DecompileMode.Dissassemble) { var container = new BytecodeContainer(data); sw.Write(container.ToString()); } else if (options.Mode == DecompileMode.Decompile) { var hlsl = DXDecompiler.Decompile(data); sw.Write(hlsl); } else if (options.Mode == DecompileMode.Debug) { sw.WriteLine(string.Join(" ", args)); var shaderBytecode = DebugBytecodeContainer.Parse(data); var result = shaderBytecode.Dump(); sw.Write(result); } else if (options.Mode == DecompileMode.DebugHtml) { var shaderBytecode = DebugBytecodeContainer.Parse(data); var result = shaderBytecode.DumpHTML(); sw.Write(result); } } else if (programType == ProgramType.DX9) { if (options.Mode == DecompileMode.Dissassemble) { var disasm = SlimShader.DX9Shader.AsmWriter.Disassemble(data); sw.Write(disasm); } else if (options.Mode == DecompileMode.Decompile) { var hlsl = SlimShader.DX9Shader.HlslWriter.Decompile(data); sw.Write(hlsl); } else if (options.Mode == DecompileMode.Debug) { sw.WriteLine(string.Join(" ", args)); var shaderType = (SlimShader.DX9Shader.ShaderType)BitConverter.ToUInt16(data, 2); if (shaderType == SlimShader.DX9Shader.ShaderType.Effect) { var reader = new DebugBytecodeReader(data, 0, data.Length); string error = ""; try { reader.ReadByte("minorVersion"); reader.ReadByte("majorVersion"); reader.ReadUInt16("shaderType"); DebugEffectChunk.Parse(reader, (uint)(data.Length - 4)); } catch (Exception ex) { error = ex.ToString(); } var dump = reader.DumpStructure(); if (!string.IsNullOrEmpty(error)) { dump += "\n" + error; } sw.Write(dump); } else { var reader = new DebugBytecodeReader(data, 0, data.Length); string error = ""; try { DebugShaderModel.Parse(reader); } catch (Exception ex) { error = ex.ToString(); } var dump = reader.DumpStructure(); if (!string.IsNullOrEmpty(error)) { dump += "\n" + error; } sw.Write(dump); } } else if (options.Mode == DecompileMode.DebugHtml) { var shaderType = (SlimShader.DX9Shader.ShaderType)BitConverter.ToUInt16(data, 2); if (shaderType == SlimShader.DX9Shader.ShaderType.Effect) { var reader = new DebugBytecodeReader(data, 0, data.Length); string error = ""; try { reader.ReadByte("minorVersion"); reader.ReadByte("majorVersion"); reader.ReadUInt16("shaderType"); DebugEffectChunk.Parse(reader, (uint)(data.Length - 4)); } catch (Exception ex) { error = ex.ToString(); } var dump = reader.DumpHtml(); if (!string.IsNullOrEmpty(error)) { dump += "\n" + error; } sw.Write(dump); } else { var reader = new DebugBytecodeReader(data, 0, data.Length); string error = ""; try { DebugShaderModel.Parse(reader); } catch (Exception ex) { error = ex.ToString(); } var dump = reader.DumpHtml(); if (!string.IsNullOrEmpty(error)) { dump += "\n" + error; } sw.Write(dump); } } } } }
public static DebugLevel9ShaderChunk Parse(DebugBytecodeReader chunkContentReader, uint chunkSize) { var result = new DebugLevel9ShaderChunk(); uint chunkSize2 = chunkContentReader.ReadUInt32("chunkSize2"); result.Version = DebugShaderVersion.ParseAon9(chunkContentReader); uint shaderSize = chunkContentReader.ReadUInt32("shaderSize"); var shaderOffset = chunkContentReader.ReadUInt32("shaderOffset"); var cbMappingCount = chunkContentReader.ReadUInt16("cbMappingCount"); var cbMappingOffset = chunkContentReader.ReadUInt16("cbMappingOffset"); var loopRegisterMappingCount = chunkContentReader.ReadUInt16("loopRegisterMappingCount"); var loopRegisterMappingOffset = chunkContentReader.ReadUInt16("loopRegisterMappingOffset"); var unk0MappingCount = chunkContentReader.ReadUInt16("unk0MappingCount"); var unk0MappingOffset = chunkContentReader.ReadUInt16("unk0MappingOffset"); var samplerMappingCount = chunkContentReader.ReadUInt16("samplerMappingCount"); var samplerMappingOffset = chunkContentReader.ReadUInt16("samplerMappingOffset"); var runtimeConstantMappingCount = chunkContentReader.ReadUInt16("runtimeConstantMappingCount"); var runtimeConstantMappingOffset = chunkContentReader.ReadUInt16("runtimeConstantMappingOffset"); if (cbMappingCount > 0) { var mappingReader = chunkContentReader.CopyAtOffset("mappingReader", chunkContentReader, cbMappingOffset); for (int i = 0; i < cbMappingCount; i++) { result.ConstantBufferMappings.Add(DebugConstantBufferMapping.Parse(mappingReader)); } } if (loopRegisterMappingCount > 0) { var mappingReader = chunkContentReader.CopyAtOffset("mappingReader", chunkContentReader, loopRegisterMappingOffset); for (int i = 0; i < loopRegisterMappingCount; i++) { result.LoopRegisterMappings.Add(DebugLoopRegisterMapping.Parse(mappingReader)); } } if (unk0MappingCount > 0) { var mappingReader = chunkContentReader.CopyAtOffset("mappingReader", chunkContentReader, unk0MappingOffset); for (int i = 0; i < unk0MappingCount; i++) { result.Unknown0Mappings.Add(DebugUnknown1Mapping.Parse(mappingReader)); } } if (samplerMappingCount > 0) { var mappingReader = chunkContentReader.CopyAtOffset("mappingReader", chunkContentReader, samplerMappingOffset); for (int i = 0; i < samplerMappingCount; i++) { result.SamplerMappings.Add(DebugSamplerMapping.Parse(mappingReader)); } // FXC dissassembly sorts sampler mappings result.SamplerMappings = result.SamplerMappings .OrderBy(s => s.TargetSampler) .ToList(); } if (runtimeConstantMappingCount > 0) { var mappingReader = chunkContentReader.CopyAtOffset("mappingReader", chunkContentReader, runtimeConstantMappingOffset); for (int i = 0; i < runtimeConstantMappingCount; i++) { result.RuntimeConstantMappings.Add(DebugRuntimeConstantMapping.Parse(mappingReader)); } } var shaderChunkReader = chunkContentReader.CopyAtOffset("shaderChunkReader", chunkContentReader, (int)shaderOffset); var byteCode = shaderChunkReader.ReadBytes("bytecode", (int)shaderSize); return(result); }
public static DebugSignatureParameterDescription Parse(DebugBytecodeReader reader, DebugBytecodeReader parameterReader, ChunkType chunkType, SignatureElementSize size, ProgramType programType) { uint stream = 0; if (size == SignatureElementSize._7 || size == SignatureElementSize._8) { stream = parameterReader.ReadUInt32("Stream"); } uint nameOffset = parameterReader.ReadUInt32("NameOffset"); var nameReader = reader.CopyAtOffset("NameReader", parameterReader, (int)nameOffset); var result = new DebugSignatureParameterDescription { SemanticName = nameReader.ReadString("SemanticName"), SemanticIndex = parameterReader.ReadUInt32("SemanticIndex"), SystemValueType = parameterReader.ReadEnum32 <Name>("SystemValueType"), ComponentType = parameterReader.ReadEnum32 <RegisterComponentType>("ComponentType"), Register = parameterReader.ReadUInt32("Register"), Stream = stream, }; result.Mask = parameterReader.ReadEnum8 <ComponentMask>("Mask"); result.ReadWriteMask = parameterReader.ReadEnum8 <ComponentMask>("ReadWriteMask"); parameterReader.ReadUInt16("MaskPadding"); if (size == SignatureElementSize._8) { MinPrecision minPrecision = parameterReader.ReadEnum32 <MinPrecision>("MinPrecision"); result.MinPrecision = minPrecision; } // This is my guesswork, but it works so far... if (chunkType == ChunkType.Osg5 || chunkType == ChunkType.Osgn || chunkType == ChunkType.Osg1 || (chunkType == ChunkType.Pcsg && programType == ProgramType.HullShader)) { result.ReadWriteMask = (ComponentMask)(ComponentMask.All - result.ReadWriteMask); } // Vertex and pixel shaders need special handling for SystemValueType in the output signature. if ((programType == ProgramType.PixelShader || programType == ProgramType.VertexShader) && (chunkType == ChunkType.Osg5 || chunkType == ChunkType.Osgn || chunkType == ChunkType.Osg1)) { if (result.Register == 0xffffffff) { switch (result.SemanticName.ToUpper()) { case "SV_DEPTH": result.SystemValueType = Name.Depth; break; case "SV_COVERAGE": result.SystemValueType = Name.Coverage; break; case "SV_DEPTHGREATEREQUAL": result.SystemValueType = Name.DepthGreaterEqual; break; case "SV_DEPTHLESSEQUAL": result.SystemValueType = Name.DepthLessEqual; break; case "SV_STENCILREF": result.SystemValueType = Name.StencilRef; break; } } else if (programType == ProgramType.PixelShader) { result.SystemValueType = Name.Target; } } return(result); }