/* * There are a few token types: * comment_token fourCC data * def_token dest_param literal_param literal_param literal_param literal_param * dcl_token decl_param dest_param * inst_token dest_param [src_param ...] * end_token */ public static ShaderModel Parse(BytecodeReader reader) { var result = new ShaderModel(); result.MinorVersion = reader.ReadByte(); result.MajorVersion = reader.ReadByte(); result.Type = (ShaderType)reader.ReadUInt16(); //SM1 shaders do not encode instruction size which rely on for reading operands. //So we won't support SM1 if (result.MajorVersion == 1) { throw new ParseException("Shader Model 1 is not supported"); } while (true) { var instruction = result.ReadInstruction(reader); if (instruction == null) { continue; } result.Tokens.Add(instruction); if (instruction.Opcode == Opcode.End) { break; } } return(result); }
public static string Decompile(ShaderModel shaderModel, string entryPoint = null) { if (shaderModel.Type == ShaderType.Effect) { return(EffectHLSLWriter.Decompile(shaderModel.EffectChunk)); } var hlslWriter = new HlslWriter(shaderModel, false, entryPoint); return(hlslWriter.Decompile()); }
public static string Disassemble(ShaderModel shaderModel) { if (shaderModel.Type == ShaderType.Effect) { var effectWriter = new EffectAsmWriter(shaderModel.EffectChunk); return(effectWriter.Decompile()); } var asmWriter = new AsmWriter(shaderModel); return(asmWriter.Decompile()); }
private void LoadConstantOutputs(ShaderModel shader) { IList <ConstantDeclaration> constantTable = shader.ConstantTable.ConstantDeclarations; _activeOutputs = new Dictionary <RegisterComponentKey, HlslTreeNode>(); _samplers = new Dictionary <RegisterKey, HlslTreeNode>(); foreach (var constant in constantTable) { if (constant.RegisterSet == RegisterSet.Sampler) { var registerKey = new RegisterKey(RegisterType.Sampler, constant.RegisterIndex); var destinationKey = new RegisterComponentKey(registerKey, 0); int samplerTextureDimension; switch (constant.ParameterType) { case ParameterType.Sampler1D: samplerTextureDimension = 1; break; case ParameterType.Sampler2D: samplerTextureDimension = 2; break; case ParameterType.Sampler3D: case ParameterType.SamplerCube: samplerTextureDimension = 3; break; default: throw new InvalidOperationException(); } var shaderInput = new RegisterInputNode(destinationKey, samplerTextureDimension); _samplers.Add(registerKey, shaderInput); } else { for (uint r = 0; r < constant.RegisterCount; r++) { if (constant.ParameterType != ParameterType.Float) { throw new NotImplementedException(); } var registerKey = new RegisterKey(RegisterType.Const, constant.RegisterIndex + r); for (int i = 0; i < 4; i++) { var destinationKey = new RegisterComponentKey(registerKey, i); var shaderInput = new RegisterInputNode(destinationKey); _activeOutputs.Add(destinationKey, shaderInput); } } } } }
private void LoadConstantOutputs(ShaderModel shader) { IList <ConstantDeclaration> constantTable = shader.ConstantTable.ConstantDeclarations; _activeOutputs = new Dictionary <RegisterComponentKey, HlslTreeNode>(); _samplers = new Dictionary <RegisterKey, HlslTreeNode>(); foreach (var constant in constantTable) { for (uint r = 0; r < constant.RegisterCount; r++) { var data = constant.GetRegisterTypeByOffset(r); int samplerTextureDimension; switch (data.Type.ParameterType) { case ParameterType.Sampler1D: samplerTextureDimension = 1; goto SamplerCommon; case ParameterType.Sampler2D: samplerTextureDimension = 2; goto SamplerCommon; case ParameterType.Sampler3D: case ParameterType.SamplerCube: samplerTextureDimension = 3; goto SamplerCommon; SamplerCommon: { var registerKey = new RegisterKey(RegisterType.Sampler, constant.RegisterIndex + r); var destinationKey = new RegisterComponentKey(registerKey, 0); var shaderInput = new RegisterInputNode(destinationKey, samplerTextureDimension); _samplers.Add(registerKey, shaderInput); } break; case ParameterType.Float: { var registerKey = new RegisterKey(RegisterType.Const, constant.RegisterIndex + r); for (int i = 0; i < 4; i++) { var destinationKey = new RegisterComponentKey(registerKey, i); var shaderInput = new RegisterInputNode(destinationKey); _activeOutputs.Add(destinationKey, shaderInput); } } break; default: throw new NotImplementedException(); } } } }
public HlslWriter(ShaderModel shader, bool doAstAnalysis = false, string entryPoint = null) { _shader = shader; _doAstAnalysis = doAstAnalysis; if (string.IsNullOrEmpty(entryPoint)) { _entryPoint = $"{_shader.Type}Main"; } else { _entryPoint = entryPoint; } }
public HlslAst Parse(ShaderModel shader) { LoadConstantOutputs(shader); int instructionPointer = 0; bool ifBlock = false; while (instructionPointer < shader.Tokens.Count) { var instruction = shader.Tokens[instructionPointer] as InstructionToken; if (instruction == null) { continue; } if (ifBlock) { if (instruction.Opcode == Opcode.Else) { ifBlock = false; } } else { if (instruction.Opcode == Opcode.IfC) { ifBlock = true; } ParseInstruction(instruction); } instructionPointer++; } Dictionary <RegisterComponentKey, HlslTreeNode> roots; if (shader.Type == ShaderType.Pixel) { roots = _activeOutputs .Where(o => o.Key.Type == RegisterType.ColorOut) .ToDictionary(o => o.Key, o => o.Value); } else { roots = _activeOutputs .Where(o => o.Key.Type == RegisterType.Output) .ToDictionary(o => o.Key, o => o.Value); } return(new HlslAst(roots)); }
private void WriteExpression(ShaderModel shader) { WriteLine("void {0}Preshader(){{", _entryPoint); Indent++; WriteLine($"// {shader.Type}_{shader.MajorVersion}_{shader.MinorVersion}"); foreach (var token in shader.Fxlc.Tokens) { WriteLine($"// {token.ToString(shader.ConstantTable, shader.Cli)}"); } if (shader.Prsi != null) { WriteLine(shader.Prsi.Dump()); } Indent--; WriteLine("}"); }
void WriteShader(string shaderName, ShaderModel shader) { WriteLine($"// {shaderName} {shader.Type}_{shader.MajorVersion}_{shader.MinorVersion} Has PRES {shader.Preshader != null}"); var funcName = shaderName; var text = ""; if (shader.Type == ShaderType.Expression) { text = ExpressionHLSLWriter.Decompile(shader, funcName); } else { text = HlslWriter.Decompile(shader, funcName); // text = text.Replace("main(", $"{funcName}("); } WriteLine(text); }
static public ShaderModel ReadShader(byte[] data) { byte minorVersion = data[0]; byte majorVersion = data[1]; ShaderType shaderType = (ShaderType)BitConverter.ToUInt16(data, 2); if (shaderType == ShaderType.Effect) { var _shader = new ShaderModel(majorVersion, minorVersion, shaderType); var bytecodeReader = new BytecodeReader(data, 4, data.Length - 4); _shader.EffectChunk = FX9.EffectContainer.Parse(bytecodeReader, (uint)(data.Length - 4)); return(_shader); } var reader = new BytecodeReader(data, 0, data.Length); return(ShaderModel.Parse(reader)); }
public AsmWriter(ShaderModel shader) { this.shader = shader; }
private void Load(ShaderModel shader) { ConstantDeclarations = shader.ConstantTable.ConstantDeclarations; foreach (var constantDeclaration in ConstantDeclarations) { RegisterType registerType; switch (constantDeclaration.RegisterSet) { case RegisterSet.Bool: registerType = RegisterType.ConstBool; break; case RegisterSet.Float4: registerType = RegisterType.Const; break; case RegisterSet.Int4: registerType = RegisterType.ConstInt; break; case RegisterSet.Sampler: registerType = RegisterType.Sampler; break; default: throw new InvalidOperationException(); } if (registerType == RegisterType.Sampler) { // Use declaration from declaration instruction instead continue; } for (uint r = 0; r < constantDeclaration.RegisterCount; r++) { var registerKey = new RegisterKey(registerType, constantDeclaration.RegisterIndex + r); var registerDeclaration = new RegisterDeclaration(registerKey); _registerDeclarations.Add(registerKey, registerDeclaration); } } foreach (var instruction in shader.Tokens.OfType <InstructionToken>().Where(i => i.HasDestination)) { if (instruction.Opcode == Opcode.Dcl) { var registerDeclaration = new RegisterDeclaration(instruction); RegisterKey registerKey = registerDeclaration.RegisterKey; _registerDeclarations.Add(registerKey, registerDeclaration); switch (registerKey.Type) { case RegisterType.Input: case RegisterType.MiscType: case RegisterType.Texture when shader.Type == ShaderType.Pixel: MethodInputRegisters.Add(registerKey, registerDeclaration); break; case RegisterType.Output: case RegisterType.ColorOut: case RegisterType.AttrOut when shader.MajorVersion == 3 && shader.Type == ShaderType.Vertex: MethodOutputRegisters.Add(registerKey, registerDeclaration); break; case RegisterType.Sampler: case RegisterType.Addr: break; default: throw new Exception($"Unexpected dcl {registerKey.Type}"); } } else if (instruction.Opcode == Opcode.Def) { var constant = new Constant( instruction.GetParamRegisterNumber(0), instruction.GetParamSingle(1), instruction.GetParamSingle(2), instruction.GetParamSingle(3), instruction.GetParamSingle(4)); _constantDefinitions.Add(constant); } else if (instruction.Opcode == Opcode.DefI) { var constantInt = new ConstantInt(instruction.GetParamRegisterNumber(0), instruction.Data[1], instruction.Data[2], instruction.Data[3], instruction.Data[4]); _constantIntDefinitions.Add(constantInt); } else { // Find all assignments to color outputs, because pixel shader outputs are not declared. int destIndex = instruction.GetDestinationParamIndex(); RegisterType registerType = instruction.GetParamRegisterType(destIndex); var registerNumber = instruction.GetParamRegisterNumber(destIndex); var registerKey = new RegisterKey(registerType, registerNumber); if (_registerDeclarations.ContainsKey(registerKey) == false) { var reg = new RegisterDeclaration(registerKey); _registerDeclarations[registerKey] = reg; switch (registerType) { case RegisterType.AttrOut: case RegisterType.ColorOut: case RegisterType.DepthOut: case RegisterType.Output: case RegisterType.RastOut: MethodOutputRegisters[registerKey] = reg; break; } } } } }
public RegisterState(ShaderModel shader) { Load(shader); }
public InstructionToken(Opcode opcode, int length, ShaderModel shaderModel) : base(opcode, length, shaderModel) { Operands = new List <Operand>(); }
private Token ReadInstruction(ShaderModel shaderModel) { uint instructionToken = ReadUInt32(); Opcode opcode = (Opcode)(instructionToken & 0xffff); Debug.Assert(opcode <= Opcode.Breakp || (opcode >= Opcode.Phase && opcode <= Opcode.End), $"Invalid opcode {opcode}"); int size; if (opcode == Opcode.Comment) { size = (int)((instructionToken >> 16) & 0x7FFF); } else { size = (int)((instructionToken >> 24) & 0x0f); } Token token = null; if (opcode == Opcode.Comment) { token = new CommentToken(opcode, size, shaderModel); for (int i = 0; i < size; i++) { token.Data[i] = ReadUInt32(); } } else { token = new InstructionToken(opcode, size, shaderModel); var inst = token as InstructionToken; for (int i = 0; i < size; i++) { token.Data[i] = ReadUInt32(); if (opcode == Opcode.Def || opcode == Opcode.DefB || opcode == Opcode.DefI) { } else if (opcode == Opcode.Dcl) { if (i == 0) { inst.Operands.Add(new DeclarationOperand(token.Data[i])); } else { inst.Operands.Add(new DestinationOperand(token.Data[i])); } } else if (i == 0 && opcode != Opcode.BreakC && opcode != Opcode.IfC && opcode != Opcode.If) { inst.Operands.Add(new DestinationOperand(token.Data[i])); } else if ((token.Data[i] & (1 << 13)) != 0) { //Relative Address mode token.Data[i + 1] = ReadUInt32(); inst.Operands.Add(new SourceOperand(token.Data[i], token.Data[i + 1])); i++; } else { inst.Operands.Add(new SourceOperand(token.Data[i])); } } } if (opcode != Opcode.Comment) { token.Modifier = (int)((instructionToken >> 16) & 0xff); token.Predicated = (instructionToken & 0x10000000) != 0; token.CoIssue = (instructionToken & 0x40000000) != 0; Debug.Assert((instructionToken & 0xA0000000) == 0, $"Instruction has unexpected bits set {instructionToken & 0xE0000000}"); } return(token); }