bool ShouldDeclareSemantics(InstructionToken instruction, RegisterType registerType) { if (registerType == RegisterType.MiscType) { return(false); } if (registerType == RegisterType.Addr) { return(false); } if (shader.Type == ShaderType.Vertex) { return(true); } if (registerType == RegisterType.Input) { switch (instruction.GetDeclUsage()) { case DeclUsage.TexCoord: case DeclUsage.Color: return(true); default: return(false); } } return(true); }
private TextureLoadOutputNode CreateTextureLoadOutputNode(InstructionToken instruction, int outputComponent) { const int TextureCoordsIndex = 1; const int SamplerIndex = 2; RegisterKey samplerRegister = instruction.GetParamRegisterKey(SamplerIndex); if (!_samplers.TryGetValue(samplerRegister, out HlslTreeNode samplerInput)) { throw new InvalidOperationException(); } var samplerRegisterInput = (RegisterInputNode)samplerInput; int numSamplerOutputComponents = samplerRegisterInput.SamplerTextureDimension; IList <HlslTreeNode> texCoords = new List <HlslTreeNode>(); for (int component = 0; component < numSamplerOutputComponents; component++) { RegisterComponentKey textureCoordsKey = GetParamRegisterComponentKey(instruction, TextureCoordsIndex, component); HlslTreeNode textureCoord = _activeOutputs[textureCoordsKey]; texCoords.Add(textureCoord); } return(new TextureLoadOutputNode(samplerRegisterInput, texCoords, outputComponent)); }
private static RegisterComponentKey GetParamRegisterComponentKey(InstructionToken instruction, int paramIndex, int component) { RegisterKey registerKey = instruction.GetParamRegisterKey(paramIndex); byte[] swizzle = instruction.GetSourceSwizzleComponents(paramIndex); int componentIndex = swizzle[component]; return(new RegisterComponentKey(registerKey, componentIndex)); }
private HlslTreeNode CreateDotProduct2AddNode(InstructionToken instruction) { var vector1 = GetInputComponents(instruction, 1, 2); var vector2 = GetInputComponents(instruction, 2, 2); var add = GetInputComponents(instruction, 3, 1)[0]; var dp2 = new AddOperation( new MultiplyOperation(vector1[0], vector2[0]), new MultiplyOperation(vector1[1], vector2[1])); return(new AddOperation(dp2, add)); }
private HlslTreeNode CreateNormalizeOutputNode(InstructionToken instruction, int outputComponent) { var inputs = new List <HlslTreeNode>(); for (int component = 0; component < 3; component++) { IList <HlslTreeNode> componentInput = GetInputs(instruction, component); inputs.AddRange(componentInput); } return(new NormalizeOutputNode(inputs, outputComponent)); }
string GetSourceName(InstructionToken instruction, int srcIndex) { string sourceRegisterName = instruction.GetParamRegisterName(srcIndex); sourceRegisterName = ApplyModifier(instruction.GetSourceModifier(srcIndex), sourceRegisterName); sourceRegisterName += instruction.GetSourceSwizzleName(srcIndex); if (instruction.IsRelativeAddressMode(srcIndex)) { sourceRegisterName += $"[{GetSourceName(instruction, srcIndex + 1)}]"; } return(sourceRegisterName); }
public string GetDestinationName(InstructionToken instruction) { int destIndex = instruction.GetDestinationParamIndex(); RegisterKey registerKey = instruction.GetParamRegisterKey(destIndex); string registerName = GetRegisterName(registerKey); registerName = registerName ?? instruction.GetParamRegisterName(destIndex); var registerLength = GetRegisterFullLength(registerKey); string writeMaskName = instruction.GetDestinationWriteMaskName(registerLength, true); return(string.Format("{0}{1}", registerName, writeMaskName)); }
private HlslTreeNode CreateDotProductNode(InstructionToken instruction) { var addends = new List <HlslTreeNode>(); int numComponents = instruction.Opcode == Opcode.Dp3 ? 3 : 4; for (int component = 0; component < numComponents; component++) { IList <HlslTreeNode> componentInput = GetInputs(instruction, component); var multiply = new MultiplyOperation(componentInput[0], componentInput[1]); addends.Add(multiply); } return(addends.Aggregate((addition, addend) => new AddOperation(addition, addend))); }
private HlslTreeNode[] GetInputComponents(InstructionToken instruction, int inputParameterIndex, int numComponents) { var components = new HlslTreeNode[numComponents]; for (int i = 0; i < numComponents; i++) { RegisterComponentKey inputKey = GetParamRegisterComponentKey(instruction, inputParameterIndex, i); HlslTreeNode input = _activeOutputs[inputKey]; var modifier = instruction.GetSourceModifier(inputParameterIndex); input = ApplyModifier(input, modifier); components[i] = input; } return(components); }
string GetDestinationName(InstructionToken instruction) { var resultModifier = instruction.GetDestinationResultModifier(); int destIndex = instruction.GetDestinationParamIndex(); string registerName = instruction.GetParamRegisterName(destIndex); const int registerLength = 4; string writeMaskName = instruction.GetDestinationWriteMaskName(registerLength, false); string destinationName = $"{registerName}{writeMaskName}"; if (resultModifier != ResultModifier.None) { //destinationName += "TODO:Modifier!!!"; } return(destinationName); }
string GetSourceName(InstructionToken instruction, int srcIndex, bool isLogicalIndex = true) { int dataIndex; if (isLogicalIndex) { // compute the actual data index, which might be different from logical index // because of relative addressing mode. // TODO: Handle relative addressing mode in a better way, // by using `InstructionToken.Operands`: // https://github.com/spacehamster/DXDecompiler/pull/6#issuecomment-782958769 // if instruction has destination, then source starts at the index 1 // here we assume destination won't have relative addressing, // so we assume destination will only occupy 1 slot, // that is, the start index for sources will be 1 if instruction.HasDestination is true. var begin = instruction.HasDestination ? 1 : 0; dataIndex = begin; while (srcIndex > begin) { if (instruction.IsRelativeAddressMode(dataIndex)) { ++dataIndex; } ++dataIndex; --srcIndex; } } else { dataIndex = srcIndex; } string sourceRegisterName = instruction.GetParamRegisterName(dataIndex); sourceRegisterName = ApplyModifier(instruction.GetSourceModifier(dataIndex), sourceRegisterName); if (instruction.IsRelativeAddressMode(dataIndex)) { sourceRegisterName += $"[{GetSourceName(instruction, dataIndex + 1, isLogicalIndex: false)}]"; } sourceRegisterName += instruction.GetSourceSwizzleName(dataIndex); return(sourceRegisterName); }
private void ParseInstruction(InstructionToken instruction) { if (instruction.HasDestination) { var newOutputs = new Dictionary <RegisterComponentKey, HlslTreeNode>(); RegisterComponentKey[] destinationKeys = GetDestinationKeys(instruction).ToArray(); foreach (RegisterComponentKey destinationKey in destinationKeys) { HlslTreeNode instructionTree = CreateInstructionTree(instruction, destinationKey); newOutputs[destinationKey] = instructionTree; } foreach (var output in newOutputs) { _activeOutputs[output.Key] = output.Value; } } }
private string GetInstructionModifier(InstructionToken instruction) { string result = ""; var modifer = instruction.GetDestinationResultModifier(); if (modifer.HasFlag(ResultModifier.Saturate)) { result += "_sat"; } if (modifer.HasFlag(ResultModifier.PartialPrecision)) { result += "_pp"; } if (modifer.HasFlag(ResultModifier.Centroid)) { result += "_centroid"; } return(result); }
private static IEnumerable <RegisterComponentKey> GetDestinationKeys(InstructionToken instruction) { int index = instruction.GetDestinationParamIndex(); RegisterKey registerKey = instruction.GetParamRegisterKey(index); if (registerKey.Type == RegisterType.Sampler) { yield break; } ComponentFlags mask = instruction.GetDestinationWriteMask(); for (int component = 0; component < 4; component++) { if ((mask & (ComponentFlags)(1 << component)) == 0) { continue; } yield return(new RegisterComponentKey(registerKey, component)); } }
private void WriteInstruction(InstructionToken instruction) { if (RemoveIndentInstruction(instruction)) { Indent--; } if (instruction.Opcode != Opcode.Comment && instruction.Opcode != Opcode.End) { WriteIndent(); } if (AddIndentInstruction(instruction)) { Indent++; } switch (instruction.Opcode) { case Opcode.Abs: WriteLine("abs{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Add: WriteLine("add{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Cmp: WriteLine("cmp{0} {1}, {2}, {3}, {4}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Dcl: string dclInstruction = "dcl"; var registerType = instruction.GetParamRegisterType(1); if (ShouldDeclareSemantics(instruction, registerType)) { dclInstruction += "_" + instruction.GetDeclSemantic().ToLower(); } WriteLine("{0}{1} {2}", dclInstruction, GetInstructionModifier(instruction), GetDestinationName(instruction)); break; case Opcode.Def: { string modifier = GetInstructionModifier(instruction); string constRegisterName = instruction.GetParamRegisterName(0); string constValue0 = SingleToString(instruction.GetParamBytes(1)); string constValue1 = SingleToString(instruction.GetParamBytes(2)); string constValue2 = SingleToString(instruction.GetParamBytes(3)); string constValue3 = SingleToString(instruction.GetParamBytes(4)); WriteLine("def{0} {1}, {2}, {3}, {4}, {5}", modifier, constRegisterName, constValue0, constValue1, constValue2, constValue3); } break; case Opcode.DefI: { string constRegisterName = instruction.GetParamRegisterName(0); WriteLine("defi{0} {1}, {2}, {3}, {4}, {5}", GetInstructionModifier(instruction), constRegisterName, instruction.Data[1], instruction.Data[2], instruction.Data[3], instruction.Data[4]); } break; case Opcode.DP2Add: WriteLine("dp2add{0} {1}, {2}, {3}, {4}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Dp3: WriteLine("dp3{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Dp4: WriteLine("dp4{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Else: WriteLine("else"); break; case Opcode.Endif: WriteLine("endif"); break; case Opcode.Exp: WriteLine("exp{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Frc: WriteLine("frc{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.If: WriteLine("if {0}", GetSourceName(instruction, 0)); break; case Opcode.IfC: WriteLine("if_{0} {1}, {2}", ((IfComparison)instruction.Modifier).ToString().ToLower(), GetSourceName(instruction, 0), GetSourceName(instruction, 1)); break; case Opcode.Log: WriteLine("log{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Lrp: WriteLine("lrp{0} {1}, {2}, {3}, {4}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Mad: WriteLine("mad{0} {1}, {2}, {3}, {4}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Max: WriteLine("max{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Min: WriteLine("min{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Mov: WriteLine("mov{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.MovA: WriteLine("mova{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Mul: WriteLine("mul{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Nop: WriteLine("nop"); break; case Opcode.Nrm: WriteLine("nrm{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Pow: WriteLine("pow{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Rcp: WriteLine("rcp{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Rsq: WriteLine("rsq{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sge: WriteLine("sge{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Slt: WriteLine("slt{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.SinCos: if (shader.MajorVersion >= 3) { WriteLine("sincos {0}, {1}", GetDestinationName(instruction), GetSourceName(instruction, 1)); } else { WriteLine("sincos {0}, {1}, {2}, {3}", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); } break; case Opcode.Sub: WriteLine("sub{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Tex: if ((shader.MajorVersion == 1 && shader.MinorVersion >= 4) || (shader.MajorVersion > 1)) { WriteLine("texld {0}, {1}, {2}", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } else { WriteLine("tex {0}", GetDestinationName(instruction)); } break; case Opcode.TexLDL: WriteLine("texldl {0}, {1}, {2}", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.TexKill: WriteLine("texkill {0}", GetDestinationName(instruction)); break; case Opcode.Rep: WriteLine("rep {0}", GetDestinationName(instruction)); break; case Opcode.EndRep: WriteLine("endrep"); break; case Opcode.DSX: WriteLine("dsx{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.DSY: WriteLine("dsy{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.TexLDD: WriteLine("texldd {0}, {1}, {2}, {3}, {4}", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3), GetSourceName(instruction, 4)); break; case Opcode.BreakC: WriteLine("break_{0} {1}, {2}", ((IfComparison)instruction.Modifier).ToString().ToLower(), GetSourceName(instruction, 0), GetSourceName(instruction, 1)); break; //TODO: Add tests for Loop, and Lit case Opcode.Loop: WriteLine("loop {0}, {1}", GetSourceName(instruction, 0), GetSourceName(instruction, 1)); break; case Opcode.EndLoop: WriteLine("endloop"); break; case Opcode.Lit: WriteLine("lit{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.ExpP: WriteLine("expp{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.LogP: WriteLine("logp{0} {1}, {2}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.M4x4: WriteLine("m4x4{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.M4x3: WriteLine("m4x3{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.M3x3: WriteLine("m3x3{0} {1}, {2}, {3}", GetInstructionModifier(instruction), GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Call: WriteLine("call {0}", GetSourceName(instruction, 0)); break; case Opcode.Ret: WriteLine("ret"); break; case Opcode.Label: WriteLine("label", GetSourceName(instruction, 0)); break; case Opcode.Comment: case Opcode.End: break; default: WriteLine(instruction.Opcode.ToString()); //WriteLine("// Warning - Not Implemented"); throw new NotImplementedException($"Instruction not implemented {instruction.Opcode}"); } }
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); }
public static void Verify(InstructionToken instruction) { //Assert(currentInstruction.Modifier == 0); //TODO: Why? Debug.Assert(!instruction.Predicated, "Instruction must not be predicated"); switch (instruction.Opcode) { case Opcode.Dcl: // https://msdn.microsoft.com/en-us/library/windows/hardware/ff549176(v=vs.85).aspx Debug.Assert(instruction.Data.Length == 2, "Dcl expected instruction length to be 2"); uint param0 = instruction.Data[0]; switch (instruction.GetParamRegisterType(1)) { case RegisterType.Sampler: Debug.Assert((param0 & 0x07FFFFFF) == 0, "Sampler param unexpected bits set"); break; case RegisterType.Input: case RegisterType.Output: case RegisterType.Texture: Debug.Assert((param0 & 0x0000FFF0) == 0, "Register param unexpected bits set"); Debug.Assert((param0 & 0x7FF00000) == 0, "Register param unexpected bits set"); break; } Debug.Assert((param0 & 0x80000000) != 0, "Register param unexpected bits set"); break; case Opcode.Def: { Debug.Assert(instruction.Data.Length == 5, "Def expected instruction length to be 5"); var registerType = instruction.GetParamRegisterType(0); Debug.Assert( registerType == RegisterType.Const || registerType == RegisterType.Const2 || registerType == RegisterType.Const3 || registerType == RegisterType.Const4, "Def unexpected register type found"); } break; case Opcode.DefI: { Debug.Assert(instruction.Data.Length == 5, "DefI expected instruction length to be 5"); var registerType = instruction.GetParamRegisterType(0); Debug.Assert(registerType == RegisterType.ConstInt, "Def unexpected register type found"); } break; case Opcode.IfC: IfComparison comp = (IfComparison)instruction.Modifier; Debug.Assert( comp == IfComparison.GT || comp == IfComparison.EQ || comp == IfComparison.GE || comp == IfComparison.LT || comp == IfComparison.NE || comp == IfComparison.LE, "IfC unknown comparison type found"); break; default: //throw new NotImplementedException(); break; } }
public string GetSourceName(InstructionToken instruction, int srcIndex) { string sourceRegisterName; RegisterKey registerKey = instruction.GetParamRegisterKey(srcIndex); var registerType = instruction.GetParamRegisterType(srcIndex); switch (registerType) { case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: case RegisterType.ConstBool: case RegisterType.ConstInt: sourceRegisterName = GetSourceConstantName(instruction, srcIndex); if (sourceRegisterName != null) { return(sourceRegisterName); } ParameterType parameterType; switch (registerType) { case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: parameterType = ParameterType.Float; break; case RegisterType.ConstBool: parameterType = ParameterType.Bool; break; case RegisterType.ConstInt: parameterType = ParameterType.Int; break; default: throw new NotImplementedException(); } var registerNumber = instruction.GetParamRegisterNumber(srcIndex); ConstantDeclaration decl = FindConstant(registerNumber); if (decl == null) { // Constant register not found in def statements nor the constant table //TODO: return($"Error {registerType}{registerNumber}"); //throw new NotImplementedException(); } var totalOffset = registerNumber - decl.RegisterIndex; var data = decl.GetRegisterTypeByOffset(totalOffset); var offsetFromMember = registerNumber - data.RegisterIndex; sourceRegisterName = decl.GetMemberNameByOffset(totalOffset); if (data.Type.ParameterClass == ParameterClass.MatrixRows) { sourceRegisterName = string.Format("{0}[{1}]", decl.Name, offsetFromMember); } else if (data.Type.ParameterClass == ParameterClass.MatrixColumns) { sourceRegisterName = string.Format("transpose({0})[{1}]", decl.Name, offsetFromMember); } break; default: sourceRegisterName = GetRegisterName(registerKey); break; } sourceRegisterName = sourceRegisterName ?? instruction.GetParamRegisterName(srcIndex); sourceRegisterName += instruction.GetSourceSwizzleName(srcIndex, true); return(ApplyModifier(instruction.GetSourceModifier(srcIndex), sourceRegisterName)); }
private string GetSourceConstantName(InstructionToken instruction, int srcIndex) { var registerType = instruction.GetParamRegisterType(srcIndex); var registerNumber = instruction.GetParamRegisterNumber(srcIndex); switch (registerType) { case RegisterType.ConstBool: //throw new NotImplementedException(); return(null); case RegisterType.ConstInt: { var constantInt = _constantIntDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantInt == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); uint[] constant = { constantInt[swizzle[0]], constantInt[swizzle[1]], constantInt[swizzle[2]], constantInt[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: throw new NotImplementedException(); /* * for (int i = 0; i < 4; i++) * { * constant[i] = -constant[i]; * } * break;*/ default: throw new NotImplementedException(); } int destLength = instruction.GetDestinationMaskLength(); switch (destLength) { case 1: return(constant[0].ToString()); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString()); } return($"int2({constant[0]}, {constant[1]})"); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString()); } return($"int3({constant[0]}, {constant[1]}, {constant[2]})"); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString()); } return($"int4({constant[0]}, {constant[1]}, {constant[2]}, {constant[3]})"); default: throw new InvalidOperationException(); } } case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: { var constantRegister = _constantDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantRegister == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); float[] constant = { constantRegister[swizzle[0]], constantRegister[swizzle[1]], constantRegister[swizzle[2]], constantRegister[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: for (int i = 0; i < 4; i++) { constant[i] = -constant[i]; } break; default: throw new NotImplementedException(); } int destLength; if (instruction.HasDestination) { destLength = instruction.GetDestinationMaskLength(); } else { if (instruction.Opcode == Opcode.If || instruction.Opcode == Opcode.IfC) { // TODO } destLength = 4; } switch (destLength) { case 1: return(constant[0].ToString(_culture)); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString(_culture)); } return(string.Format("float2({0}, {1})", constant[0].ToString(_culture), constant[1].ToString(_culture))); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString(_culture)); } return(string.Format("float3({0}, {1}, {2})", constant[0].ToString(_culture), constant[1].ToString(_culture), constant[2].ToString(_culture))); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString(_culture)); } return(string.Format("float4({0}, {1}, {2}, {3})", constant[0].ToString(_culture), constant[1].ToString(_culture), constant[2].ToString(_culture), constant[3].ToString(_culture))); default: throw new InvalidOperationException(); } } default: return(null); } }
private string GetDestinationName(InstructionToken instruction) { return(_registers.GetDestinationName(instruction)); }
private string GetSourceName(InstructionToken instruction, int srcIndex) { return(_registers.GetSourceName(instruction, srcIndex)); }
private void WriteInstruction(InstructionToken instruction) { WriteIndent(); WriteLine($"// {instruction}"); switch (instruction.Opcode) { case Opcode.Def: case Opcode.DefI: case Opcode.Dcl: case Opcode.End: return; // these opcodes doesn't need indents: case Opcode.Else: Indent--; WriteIndent(); WriteLine("} else {"); Indent++; return; case Opcode.Endif: Indent--; WriteIndent(); WriteLine("}"); return; case Opcode.EndRep: Indent--; _iterationDepth--; WriteIndent(); WriteLine("}"); return; } WriteIndent(); switch (instruction.Opcode) { case Opcode.Abs: WriteLine("{0} = abs({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Add: WriteLine("{0} = {1} + {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Cmp: // TODO: should be per-component WriteLine("{0} = ({1} >= 0) ? {2} : {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.DP2Add: WriteLine("{0} = dot({1}, {2}) + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Dp3: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Dp4: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Exp: WriteLine("{0} = exp2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Frc: WriteLine("{0} = frac({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.If: WriteLine("if ({0}) {{", GetSourceName(instruction, 0)); Indent++; break; case Opcode.IfC: if ((IfComparison)instruction.Modifier == IfComparison.GE && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} == 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else if ((IfComparison)instruction.Modifier == IfComparison.LT && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} != 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else { string ifComparison; switch ((IfComparison)instruction.Modifier) { case IfComparison.GT: ifComparison = ">"; break; case IfComparison.EQ: ifComparison = "=="; break; case IfComparison.GE: ifComparison = ">="; break; case IfComparison.LE: ifComparison = "<="; break; case IfComparison.NE: ifComparison = "!="; break; case IfComparison.LT: ifComparison = "<"; break; default: throw new InvalidOperationException(); } WriteLine("if ({0} {2} {1}) {{", GetSourceName(instruction, 0), GetSourceName(instruction, 1), ifComparison); } Indent++; break; case Opcode.Log: WriteLine("{0} = log2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Lrp: WriteLine("{0} = lerp({2}, {3}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Mad: WriteLine("{0} = {1} * {2} + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Max: WriteLine("{0} = max({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Min: WriteLine("{0} = min({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Mov: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.MovA: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Mul: WriteLine("{0} = {1} * {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Nrm: WriteLine("{0} = normalize({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Pow: WriteLine("{0} = pow({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Rcp: WriteLine("{0} = 1 / {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Rsq: WriteLine("{0} = 1 / sqrt({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sge: if (instruction.GetSourceModifier(1) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(2) == SourceModifier.Abs && instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1) == instruction.GetParamRegisterName(2) + instruction.GetSourceSwizzleName(2)) { WriteLine("{0} = ({1} == 0) ? 1 : 0;", GetDestinationName(instruction), instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)); } else { WriteLine("{0} = ({1} >= {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } break; case Opcode.Slt: WriteLine("{0} = ({1} < {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.SinCos: WriteLine("sincos({1}, {0}, {0});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sub: WriteLine("{0} = {1} - {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Tex: if ((_shader.MajorVersion == 1 && _shader.MinorVersion >= 4) || (_shader.MajorVersion > 1)) { WriteLine("{0} = tex2D({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } else { WriteLine("{0} = tex2D();", GetDestinationName(instruction)); } break; case Opcode.TexLDL: WriteLine("{0} = tex2Dlod({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Comment: { byte[] bytes = new byte[instruction.Data.Length * sizeof(uint)]; Buffer.BlockCopy(instruction.Data, 0, bytes, 0, bytes.Length); var ascii = FormatUtil.BytesToAscii(bytes); WriteLine($"// Comment: {ascii}"); break; } case Opcode.Rep: WriteLine("for (int it{0} = 0; it{0} < {1}; ++it{0}) {{", _iterationDepth, GetSourceName(instruction, 0)); _iterationDepth++; Indent++; break; case Opcode.TexKill: WriteLine("clip({0});", GetDestinationName(instruction)); break; default: throw new NotImplementedException(instruction.Opcode.ToString()); } }
public RegisterDeclaration(InstructionToken declInstruction) { RegisterKey = declInstruction.GetParamRegisterKey(1); _semantic = declInstruction.GetDeclSemantic(); _maskedLength = declInstruction.GetDestinationMaskedLength(); }
private HlslTreeNode CreateInstructionTree(InstructionToken instruction, RegisterComponentKey destinationKey) { int componentIndex = destinationKey.ComponentIndex; switch (instruction.Opcode) { case Opcode.Dcl: { var shaderInput = new RegisterInputNode(destinationKey); return(shaderInput); } case Opcode.Def: { var constant = new ConstantNode(instruction.GetParamSingle(componentIndex + 1)); return(constant); } case Opcode.DefI: { var constant = new ConstantNode(instruction.GetParamInt(componentIndex + 1)); return(constant); } case Opcode.DefB: { throw new NotImplementedException(); } case Opcode.Abs: case Opcode.Add: case Opcode.Cmp: case Opcode.Frc: case Opcode.Lrp: case Opcode.Mad: case Opcode.Max: case Opcode.Min: case Opcode.Mov: case Opcode.Mul: case Opcode.Pow: case Opcode.Rcp: case Opcode.Rsq: case Opcode.SinCos: case Opcode.Sge: case Opcode.Slt: { HlslTreeNode[] inputs = GetInputs(instruction, componentIndex); switch (instruction.Opcode) { case Opcode.Abs: return(new AbsoluteOperation(inputs[0])); case Opcode.Cmp: return(new CompareOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Frc: return(new FractionalOperation(inputs[0])); case Opcode.Lrp: return(new LinearInterpolateOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Max: return(new MaximumOperation(inputs[0], inputs[1])); case Opcode.Min: return(new MinimumOperation(inputs[0], inputs[1])); case Opcode.Mov: return(new MoveOperation(inputs[0])); case Opcode.Add: return(new AddOperation(inputs[0], inputs[1])); case Opcode.Mul: return(new MultiplyOperation(inputs[0], inputs[1])); case Opcode.Mad: return(new MultiplyAddOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Pow: return(new PowerOperation(inputs[0], inputs[1])); case Opcode.Rcp: return(new ReciprocalOperation(inputs[0])); case Opcode.Rsq: return(new ReciprocalSquareRootOperation(inputs[0])); case Opcode.SinCos: if (componentIndex == 0) { return(new CosineOperation(inputs[0])); } return(new SineOperation(inputs[0])); case Opcode.Sge: return(new SignGreaterOrEqualOperation(inputs[0], inputs[1])); case Opcode.Slt: return(new SignLessOperation(inputs[0], inputs[1])); default: throw new NotImplementedException(); } } case Opcode.Tex: case Opcode.TexLDL: return(CreateTextureLoadOutputNode(instruction, componentIndex)); case Opcode.DP2Add: return(CreateDotProduct2AddNode(instruction)); case Opcode.Dp3: case Opcode.Dp4: return(CreateDotProductNode(instruction)); case Opcode.Nrm: return(CreateNormalizeOutputNode(instruction, componentIndex)); default: throw new NotImplementedException($"{instruction.Opcode} not implemented"); } }
//Refer https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-vs-instructions-vs-3-0 //Refer https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-ps-3-0 public static int GetInstructionSlotCount(this InstructionToken token) { switch (token.Opcode) { case Opcode.Dcl: case Opcode.Def: case Opcode.DefB: case Opcode.DefI: case Opcode.Label: case Opcode.Comment: case Opcode.End: return(0); case Opcode.Abs: case Opcode.Add: case Opcode.Break: case Opcode.Dp3: case Opcode.Dp4: case Opcode.Dst: case Opcode.Else: case Opcode.Endif: case Opcode.Exp: case Opcode.Frc: case Opcode.Log: case Opcode.LogP: case Opcode.Mad: case Opcode.Max: case Opcode.Min: case Opcode.Mov: case Opcode.MovA: case Opcode.Mul: case Opcode.Nop: case Opcode.Rcp: case Opcode.Ret: case Opcode.Rsq: case Opcode.SetP: case Opcode.Sge: case Opcode.Slt: case Opcode.Sub: case Opcode.Cmp: return(1); case Opcode.Lrp: return(1); case Opcode.Call: case Opcode.Crs: case Opcode.EndLoop: case Opcode.EndRep: case Opcode.M3x2: case Opcode.DP2Add: case Opcode.DSX: case Opcode.DSY: case Opcode.TexKill: return(2); case Opcode.CallNZ: case Opcode.BreakC: case Opcode.Breakp: case Opcode.If: case Opcode.IfC: case Opcode.Lit: case Opcode.Loop: case Opcode.M3x3: case Opcode.M4x3: case Opcode.Nrm: case Opcode.Pow: case Opcode.Rep: case Opcode.Sgn: case Opcode.TexLDD: return(3); case Opcode.M3x4: case Opcode.M4x4: return(4); //TODO: can't find opcode //case Opcode.TexLdb: // return 6 case Opcode.SinCos: return(8); case Opcode.TexLDL: { var textureType = token.GetDeclSamplerTextureType(); if (textureType == SamplerTextureType.Cube) { return(5); } else { return(2); } } //TexLD case Opcode.Tex: { var textureType = token.GetDeclSamplerTextureType(); if (textureType == SamplerTextureType.Cube) { return(4); } else { return(1); } } //Guessing case Opcode.ExpP: return(1); default: throw new NotImplementedException($"Instruction not implemented {token.Opcode}"); } }
Token ReadInstruction(BytecodeReader reader) { uint instructionToken = reader.ReadUInt32(); Opcode opcode = (Opcode)(instructionToken & 0xffff); int size; if (opcode == Opcode.Comment) { size = (int)((instructionToken >> 16) & 0x7FFF); } else { size = (int)((instructionToken >> 24) & 0x0f); } Token token = null; if (opcode == Opcode.Comment) { var fourCC = reader.ReadUInt32(); if (KnownCommentTypes.ContainsKey(fourCC)) { var commentReader = reader.CopyAtCurrentPosition(); reader.ReadBytes(size * 4 - 4); switch (KnownCommentTypes[fourCC]) { case CommentType.CTAB: ConstantTable = ConstantTable.Parse(commentReader); return(null); case CommentType.C**T: Cli = CliToken.Parse(commentReader); return(null); case CommentType.FXLC: Fxlc = FxlcBlock.Parse(commentReader); return(null); case CommentType.PRES: Preshader = Preshader.Parse(commentReader); return(null); case CommentType.PRSI: Prsi = PrsiToken.Parse(commentReader); return(null); } } token = new CommentToken(opcode, size, this); token.Data[0] = fourCC; for (int i = 1; i < size; i++) { token.Data[i] = reader.ReadUInt32(); } } else { token = new InstructionToken(opcode, size, this); var inst = token as InstructionToken; for (int i = 0; i < size; i++) { token.Data[i] = reader.ReadUInt32(); if (opcode == Opcode.Def || opcode == Opcode.DefB || opcode == Opcode.DefI) { if (i == 0) { inst.Operands.Add(new DestinationOperand(token.Data[i])); } } 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.HasDestination()) { if ((token.Data[i] & (1 << 13)) != 0) { //Relative Address mode token.Data[i + 1] = reader.ReadUInt32(); inst.Operands.Add(new DestinationOperand(token.Data[i], token.Data[i + 1])); i++; } else { inst.Operands.Add(new DestinationOperand(token.Data[i])); } } else if ((token.Data[i] & (1 << 13)) != 0) { //Relative Address mode token.Data[i + 1] = reader.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); }